Spring return selected field from domain - spring

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.

Related

Query parameters binding into DTO, how to ignore specific param?

Is there any good way to ignore some request query parameters from binding to DTO parameters?
#Data // setters and getters
class Dto {
private String param1;
private String param2;
}
#GetMapping("/hello-world")
#ResponseBody
public ResponseEntity<Dto> sayHello(Dto params)
{ ... }
I would like to exclude binding of specific param in such case.
After some research I can't find any solution for it, any help?

Spring Response\Request body templates

Let me explain a problem. Suppose I have an entity class User:
public class User {
private UUID id;
private String login;
private String password;
private String firstName;
private String lastName;
private String email;
private int age;
// ... more fields and default getters and setters
}
In addition, I have two DTO classes:
public class UserLogin {
private UUID id;
private String login;
// ... getters and setters
}
public class UserLoginEmail {
private UUID id;
private String login;
private String email;
// ... getters and setters
}
Let's take a look to class UserController that has UserLoginEmail as request body and UserLogin as response body:
#RestController("/users")
public class UserController {
#PutMapping
public UserLogin someRequest(UserLoginEmail user) {
// ...
}
}
What is the best way to create some kind of projections in Spring Boot? Can I create an interface with required fields and just put them in the Java method as parameters (or some other way)? I want to build DTO classes with the least effort and agile in my code.
You could use JSON Views with Jackson with which you could define different views on a per endpoint basis (check https://www.baeldung.com/jackson-json-view-annotation for more details).
But in your case, I wouldn't do that. One of your DTOs is a request and the other is a response so you shouldn't mix them together in a single DTO. Even more than that, I don't really like JSON Views because they are simply hard to follow and the code becomes harder to read. Abstractions and code reusability are usually good but it makes the code much harder to read and for the case of DTOs I much more prefer to be explicit and have multiple DTOs even that they are similar. With this approach, you will make it possible to easily change one of the DTOs without affecting anything else, which is not the case when you reuse them in any way.
Having said that, keep both DTOs, but I would rename them: UserLoginRequest and UserLoginResponse.

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.

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;

Have one Rest repository json with everything and one with fields excluded

I have two entities: Book and Category and a repository for both. In the controller, I have set up the methods correctly as such:
#RequestMapping(value="/books", method = RequestMethod.GET)
#CrossOrigin
public #ResponseBody List<Book> bookListRest() {
return (List<Book>) bookRepository.findAll();
}
This obviously shows all books and every field in the entity that isn't #JsonIgnore'd. The problem is, I need to have:
One page with Book data (book name, author name, isbn..) without category
One page with Category data (Category name) without books
One page with Everything (book data along with categories where they belong in)
How can one accomplish this?
I somehow need to in a way ignore #jsonignore on some occasions. Should I make a new entity that extends say, Question and also make a repository for that? Surely that can't be the correct way to do this.
As khalid Ahmed Said you can use costum dtos or you can add Filters to ignore specific fields in Jackson. First, we need to define the filter on the java object:
#JsonFilter("myFilterBook")
public class Book{
...
}
#JsonFilter("myFilterCategory")
public class Category{
...
}
Before you return your ResponseBody you try to use ObjectMapper (Jackson):
The case of one page with Book data (book name, author name, isbn..) without category:
ObjectMapper mapper = new ObjectMapper();
SimpleBeanPropertyFilter theFilter = SimpleBeanPropertyFilter
.serializeAllExcept("category");
FilterProvider filters = new SimpleFilterProvider()
.addFilter("myFilterBook", theFilter);
String dtoAsString = mapper.writer(filters).writeValueAsString(book);
You can do the same think by putting what you want o ignore for the other example.
And for more details to ignore field during marshalling with jackson you can check here
What about using DTOs data transfer objects
you can create multiple DTOs to use them in the response of your API
DTO is a pojo class that customize the returning data from your entity
public class BookWithoutCategoryDTO {
private String name;
private String authorName;
.....
/// and make setters and getters for them
}
public class BookWithCategoryDTO {
private String name;
private String authorName;
private String category;
.....
/// and make setters and getters for them
}
and create your custom mapper to convert from Book to BookDTO

Resources