How to validate DTO string field is one of specified values - spring

My spring boot application has a DTO class for creating a task.
public class CreateTaskDTO {
#NotBlank
private String status;
}
I want the type field to be one of these values: "DONE", "IN_PROGRESS", "OPEN".
Is there hibernate constraints or any other workarounds I can validate thie field?

public enum Status() {
DONE, IN_PROGRESS, OPEN
}
public class CreateTaskDTO {
#NotNull
private Status status;
}
Enum must be created. The created enum should also be used in the DTO.

Related

Spring boot REST API best way to choose in client side which field to load

Hi I have implemented a mock solution to my problem and I'm pretty sure something better already exist.
Here's that I want to achieve :
I have created a point to load categories with or without subCategories
/api/categories/1?fields=subCategories
returns
{
"id":"1",
"name":"test",
"subCategories":[{
"id":"1",
"name":"test123"
}]
}
/api/categories/1
returns
{
"id":"1",
"name":"test"
}
My entities
#Entity
class Category{
#Id
private String id;
private String name;
private Set<SubCategory> subCategories;
}
#Entity
class SubCategory{
#Id
private String id;
private String name;
}
I have removed services since this is not the point.
I've created CategoryDTO and SubCategoryDTO classes with the same fields as Category and SubCategory
The converter
class CategoryDTOConverter{
CategoryDTO convert(Category category,String fields){
CategoryDTO dto=new CategoryDTO();
dto.setName(category.getName());
if(StringUtils.isNotBlank(fields) && fields.contains("subCategories"){
category.getSubCategories().forEach(s->{
dto.getSubcategories().add(SubCategoryDTOConverter.convert(s));
}
}
}
}
I used com.cosium.spring.data.jpa.entity.graph.repository to create an EntityGraph from a list of attribute path
#Repository
interface CategoryRepository extends EntityGraphJpaRepository<Category, String>{
Optional<T> findById(String id,EntityGraph entityGraph);
}
Controller
#RestController
#CrossOrigin
#RequestMapping("/categories")
public class CategoryController {
#GetMapping(value = "/{id}")
public ResponseEntity<CategoryDTO> get(#PathVariable("id") String id, #RequestParam(value="fields",required=false) String fields ) throws Exception {
Optional<Category> categOpt=repository.findById(id,fields!=null?EntityGraphUtils.fromAttributePaths(fields):null);
if(categOpt.isEmpty())
throws new NotFoundException();
return ResponseEntity.ok(categoryDTOConverter.convert(categOpt.get(),fields);
}
}
This is a simple example to illustrate what I need to do
I don't want to load fields that clients doesn't want to use
How could I do this in a better way ?
Take a look at GraphQL since it is a perfect match for your use case. With GraphQL it is the client that decides which attributes it wants to receive by providing in the POST request body exactly which attributes are needed to be included in the response. This is way more manageable than trying to handle all this on your own.
Spring Boot recently added its own Spring GraphQL library, so it is quite simple to integrate it in your Spring Boot app.

Spring data mongo - unique random generated field

I'm using spring data mongo. I have a collection within a document that when I add an item to it I would like to assign a new automatically generated unique identifier to it e.g. (someGeneratedId)
#Document(collection = "questionnaire")
public class Questionnaire {
#Id
private String id;
#Field("answers")
private List<Answer> answers;
}
public class Answer {
private String someGeneratedId;
private String text;
}
I am aware I could use UUID.randomUUID() (wrapped in some kind of service) and set the value, I was just wondering if there was anything out of the box that can handle this? From here #Id seems to be specific to _id field in mongo:
The #Id annotation tells the mapper which property you want to use for
the MongoDB _id property
TIA
No there is no out of the box solution for generating ids for properties on embedded documents.
If you want to keep this away from your business-logic you could implement a BeforeConvertCallback which generates the id's for your embedded objects.
#Component
class BeforeConvertQuestionnaireCallback implements BeforeConvertCallback<Questionnaire> {
#Override
public Questionnaire onBeforeConvert(#NonNull Questionnaire entity, #NonNull String collection) {
for (var answer : entity.getAnswers()) {
if (answer.getId() == null) {
answer.setId(new ObjectId().toString());
}
}
return entity;
}
}
You could also implement this in a more generic manner:
Create a new annotation: #AutogeneratedId.
Then listen to all BeforeConvertCallback's of all entities and iterate through the properties with reflection. Each property annotated with the new annotation gets a unique id if null.

Spring Boot : How to do REST validation based on input group?

I have a form in which :
firstname and lastname are mandatory fields for registered user.
ssn for new user.
contract number for owner.
So, on clicking the submit button, REST API (connect API) is called with values
from either of the above groups.
My bean class has members :
FN
LN
SSN
contractNum
How do I validate using bean/hibernate validator and identify which group has been passed ?
From the Hibernate Documentation, you can read for detail
https://hibernate.org/validator/
Hibernate Validator allows to express and validate application
constraints. The default metadata source are annotations, with the
ability to override and extend through the use of XML. It is not tied
to a specific application tier or programming model and is available
for both server and client application programming. But a simple
example says more than 1000 words:
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
public class User {
#NotNull
private String firstName;
#NotNull
private String lastName;
#NotNull
private String ssn;
}
Bean Validation is best used for simple validation logic. If your validation requires more complexity, use Spring's Validator interface instead.
I don't know the context domain, so I'll just call your bean "Form" with all String fields for the example:
public class Form {
private String firstName;
private String lastName;
private String ssn;
private String contractNumber;
// getters and setters
}
Then create a validator for this class:
public class FormValidator implements Validator {
public boolean supports(Class clazz) {
return Form.class.isAssignableFrom(clazz);
}
public void validate(Object target, Errors errors) {
Form form = (Form) target;
// validation logic
}
}
Then you can simply use it like this:
Form form = ...;
Validator validator = new FormValidator();
Errors errors = new Errors();
validator.validate(form, errors);
if (errors.hasErrors() {
// not valid
} else {
// is valid
}

How do I get Spring's Data Rest Repository to retrieve data by its name instead of its id

I am using Spring Data's Rest Repositories from spring-boot-starter-data-rest, with Couchbase being used as the underlining DBMS.
My Pojo for the object is setup as so.
#Document
public class Item{
#Id #GeneratedValue(strategy = UNIQUE)
private String id;
#NotNull
private String name;
//other items and getters and setters here
}
And say the Item has an id of "xxx-xxx-xxx-xxx" and name of "testItem".
Problem is, that when I want to access the item, I need to be accessible by /items/testItem, but instead it is accessible by /items/xxx-xxx-xxx-xxx.
How do I get use its name instead of its generated id, to get the data.
I found out the answer to my own question.
I just need to override the config for the EntityLookup.
#Component
public class SpringDataRestCustomization extends RepositoryRestConfigurerAdapter {
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.withEntityLookup().forRepository(UserRepository.class).
withIdMapping(User::getUsername).
withLookup(UserRepository::findByUsername);
}
}
Found the info here, though the method name changed slightly.
https://github.com/spring-projects/spring-data-examples/tree/master/rest/uri-customization
If you want query the item by name and want it perform as querying by id,you should make sure the name is unique too.You cant identify a explicit object by name if all objects have a same name,right?
With jpa you could do it like:
#NotNull
#Column(name="name",nullable=false,unique=true)
private String name;

Spring return selected field from domain

I've the following domain and needs to return selected field in response to client. How can I achieve that using Spring?
public class Vehicle {
private String vehicleId;
private Long dateCreated;
private String ownerId;
private String colourCode;
private String engineNumber;
private String transmission;
//getters & setters
}
My objective is to return only colourCode and transmission fields to client request. I've read about DTO and seems like I can achieve my objective with DTO but I don't find any good example how to implement it. Is DTO is the correct way to achieve my objective ?
Basically you just create VehicleDTO class with parameters you need
public class VehicleDTO {
private String colourCode;
private String transmission;
//getters and setters
}
and then in your code you construct VehicleDTO from your Vehicle class. Fortunately, we have BeansUtils class from Spring, that uses reflection to copy properties of one object to another, because you do not want to repeat logic for copying properties for every object. So it would be something like:
BeanUtils.copyProperties(v1, dto);
At the end your return VehicleDTO in your response instead of Vehicle
You can return IVehicle interface which exposes your properties of choice
public interface IVehicle {
String getTransmission();
String getColourCode();
}
and your Vehicle implents it
public class Vehicle implements IVehicle{ }
There are various ways you can achieve what you want.
You can add relevant usecase / APi specific DTO for the resource.
e.g. If your API return the vehical general details you may want to expose some level of details,
public class VehicleDetailsDTO {
private String colourCode;
private String transmission;
private String engineNumber; //more
//getters and setters
}
You can then either use BeanUtils or Dozzer to convert your Vehical resource to transportable object like your DTO.
BeanUtils : http://commons.apache.org/proper/commons-beanutils/
Dozzer : http://dozer.sourceforge.net/documentation/mappings.html
Assuming you use JSON as output format and Jackson as serialization engine (default in Spring MVC), you can tell Jackson to not serialize null properties. Now you just need to populate the properties you need and can return the original business object.

Resources