Can we Convert more than one entity into single Dto in Spring boot - spring

Can we Convert More Than One Entity into single DTO
I have two entity Car And Truck and I want to pass single Entity VehcileDto on Thymleaf page is it possible or not?

That's not necessarily a Spring Boot topic but rather a Java topic.
Say you got the following classes:
/**
* In this class you would define the Car Entity with all its fields and relations
*/
public class CarEntity {
private String someCarField;
private String anotherCarField;
public String getSomeCarField() {
return someCarField;
}
public void setSomeCarField(String someCarField) {
this.someCarField = someCarField;
}
public String getAnotherCarField() {
return anotherCarField;
}
public void setAnotherCarField(String anotherCarField) {
this.anotherCarField = anotherCarField;
}
}
Your Truck Entity would look very similar.
Then you define a DTO:
/**
* Here you would define the DTO. The DTO is just two Entities in one WrapperObject (See Definition of DTO in Java).
* This includes all the fields you want to use on your thymeleaf UI.
* This is the DTO you would put into your model using the MVC Controller
*/
public class VehicleDTO {
private String someTruckField;
private String anotherTruckField;
private String someCarField;
private String anotherCarField;
public VehicleDTO(String someTruckField, String anotherTruckField, String someCarField, String anotherCarField) {
this.someTruckField = someTruckField;
this.anotherTruckField = anotherTruckField;
this.someCarField = someCarField;
this.anotherCarField = anotherCarField;
}
}
This is a class that contains both Entities.
Then you would need a factory to properly create the DTO:
/**
* This is a Factory class which creates a VehicleDTO
*/
public class VehicleDTOFactory {
public VehicleDTO createVehicleDTO(CarEntity car, TruckEntity truck){
return new VehicleDTO(truck.getSomeTruckField(),
truck.getAnotherTruckField(),
car.getSomeCarField(),
car.getAnotherCarField());
}
}
Then over the MVC controller you would call the factory Method and fill the parameters with Entities from your database.
This is just a very basic example.
I'd recommend looking closer into why Factories and DTOs are used

Related

Spring data elasticsearch embedded field mapping

I'm struggling with mappings some field. I looked for an answer but couldn't find anything solving my case. Let's cut to the chase.
I have my document class
#Doucment
public class DocumentClass {
#Field(type = FieldType.Nested)
private EmployeeId employeeId;
}
An EmployeeId is wrapper for my uuid identifier. This object has nothing but just getters and setters and jackson annotations. The thing is that object extends some base class so such objects like EmployeeId can inherit this object. This super class has field id and this causes the problem. When I post some data to elasticsearch then it looks like this:
{
"employeeId": {
"id": "someUUID"
}
}
But I want to map this to be like:
{
"employeeId": "someUUID"
}
I wonder if there is a way to flatten this object.
If I get it right, you want to convert your EmployeeId class to a String and back. You have 2 possibilities to do that:
Using a property converter
If you only want to convert an EmployeeId in this entity and might keep it as it is in another, you should use a property converter that is only registered for this property:
import org.springframework.data.elasticsearch.core.mapping.PropertyValueConverter;
public class EmployeeIdConverter implements PropertyValueConverter {
#Override
public Object write(Object value) {
return value instanceof EmployeeId employeeId ? employeeId.getId() : value.toString();
}
#Override
public Object read(Object value) {
return new EmployeeId(value.toString());
}
}
This converter must be registered on the property, notice that the field type is set to Keyword as it probably should not be analysed:
import org.springframework.data.elasticsearch.annotations.ValueConverter;
#Document
public class DocumentClass {
#Field(type = FieldType.Keyword)
#ValueConverter(EmployeeIdConverter.class)
private EmployeeId employeeId;
}
Using a global converter
If you are using this EmployeeId at several places you might want register globally 2 converters for the two conversion directions:
#WritingConverter
public class EmployeeIdToString implements Converter<EmployeeId, String>{
#Nullable
#Override
public String convert(EmployeeId employeeId) {
return employeeId.getId();
}
}
#ReadingConverter
public class StringToEmployeeId implements Converter<String, EmployeeId>{
#Nullable
#Override
public EmployeeId convert(String id) {
return new EmployeeId(id);
}
}
To register these, you need to provide a custom client configuration (see the documentation):
#Configuration
public class MyClientConfig extends ElasticsearchConfiguration {
#Override
public ClientConfiguration clientConfiguration() {
return ClientConfiguration.builder()
.connectedTo("localhost:9200")
.build();
}
#Override
public ElasticsearchCustomConversions elasticsearchCustomConversions() {
Collection<Converter<?, ?>> converters = new ArrayList<>();
converters.add(new EmployeeIdToString());
converters.add(new StringToEmployeeId());
return new ElasticsearchCustomConversions(converters);
}
}
In this case, only the field type needs to be adjusted
#Document
public class DocumentClass {
#Field(type = FieldType.Keyword)
private EmployeeId employeeId;
}
I am guessing you have an Id field which is a string.
You need to put a #JsonValue annotation on that field to make jackson serialize it the way you want.
Field annotated by JsonValue will be used to serialize your pojo into json.
If your Id field is private, then add the annotation on the getter of that field.
https://fasterxml.github.io/jackson-annotations/javadoc/2.8/com/fasterxml/jackson/annotation/JsonValue.html

Use converter to get form data parameters into a map inside a dto

I have a controller method in spring boot:
#PostMapping(produces = "text/html")
public String create(#Valid myDTO myDTO, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest) {
// Omissions
return "redirect:/blue/tar/";
}
I have a dto:
public class MyDTO {
private Long id;
private List<FooBar> objects;
public MyDTO(Long id, List<FooBar> objects) {
this.id = id;
this.objects = objects;
}
public Long getId() {
return id;
}
public List<FooBar> getObjects() {
return objects;
}
}
And I have a converter, which i have added to the converterRegistry in spring:
private Converter<String, FooBar> getStringToLegalEntityConverter() {
return new org.springframework.core.convert.converter.Converter<>() {
public FooBar convert(#NotNull String id) {
return //* convert id to FooBar structure*//
}
};
}
My web form send form data. E.g:
fooBar: 1
fooBar: 3
fooBar: 4
And the above code handles this perfectly. The converter is called three times with 1, 3 and 4. The result a bit magically appears as a list with three FooBar objects in the dto in the controller.
The above works.
I attempted to use a map in MyDTO instead. Spring complains that there is no converter from String -> Map.
If i add one (which feels wrong, since there was no converter from String -> List before), it only enters the converter once with the last value. (4, in the example above).
So is there a solution here to get spring to allow me to manually convert a series of form params to a map in such a way that they end up in a DTO like that?
Below is my attempt which fails. Since spring only attempts to convert one value to fit in the map in the DTO. I would have needed the converter to be called with all the form parameters at once:
private Converter<String, Map<Long, FooBar>> attempt() {
return new org.springframework.core.convert.converter.Converter<>() {
public Map<Long, FooBar> convert(#NotNull String aString) {
/* Say if aString is the formparameters as "1,3,4" then i'd turn those into keys and then fetch their values from a db */
return /* The map */
}
};
}
Similar but I don't think the answers there are applicable: How to get Form data as a Map in Spring MVC controller?

Spring MongoRepository custom query

Hi I am new to using Spring with MongoRepository and I'm working on creating a custom query for MongoDB using Spring's MongoRepository.
What I would like to do is return a custom query for another variable in my model instead of the Object id.
for my model I have:
#Document(collection = "useraccount")
public class UserAccounts {
#Id
private String id;
private String accountNumber;
private String firstName;
private String lastName;
// getters and setters
}
inside of my repository I just extend the generic MongoRepository:
#Repository
public interface UserAccountsRepository extends MongoRepository<UserAccounts, String> {
}
I am trying to create a custom query that returns the accountNumber inside of my UserAccountsService:
#Service
public class UserAccountsService {
private final UserAccountsRepository userAccountsRepository;
public UserAccountsService(UserAccountsRepository userAccountsRepository) {
this.userAccountsRepository = userAccountsRepository;
}
// generic find by Object id
public UserAccounts findOne(String id) {
Optional<UserAccounts> userAccountsOptional =
userAccountsRepository.findById(id);
if(!userAccountsOptional.isPresent()) {
throw new RuntimeException("User Account Not Found");
}
return userAccountsOptional.get();
}
// would like to implement custom query to return UserAccount if
// found by accountNumber variable
public UserAccounts findOneByUserAccountNumber(String accountNumber) {
return dormantAccountsRepository.findOne(*need query here*);;
}
}
How would I go about creating a custom query to find a User Account by the accountNumber instead of the object id?
Any help would be great thanks!

Spring Boot validation with Hibernate Validator

Anyone know if it`s possible to create one method in my entity, to execute when I put the annotation #Valid in my class?
Example:
I have this Object:
public class Area {
#NotEmpty
private String unidade;
#NotNull
private double tamanho;
public String getUnidade() {
return unidade;
}
public void setUnidade(String unidade) {
this.unidade = unidade;
}
public double getTamanho() {
return tamanho;
}
public void setTamanho(double tamanho) {
this.tamanho = tamanho;
}
}
And I have this method:
#RestController
#RequestMapping("/recolhimento")
public class RecolhimentoController {
#RequestMapping(method = RequestMethod.GET)
public boolean getRecolhimento(#Valid Area area){
...
}
}
so when I call this method the Spring Boot will validate my model Area( but I want to create one method that will be execute when I use #Valid.
it`s possible? how?
Yes, it is possible.
You can find examples in this project: https://github.com/malkusch/validation

Is there any way to bind different query string pertaining to same field of #ModelAttribute in #Controller

Class ExampleModel {
private String product;
}
#RequestMapping("/products")
public getProducts( #ModelAttribute ExampleModel model){
}
* What I want is to populate model with product class member if I hit the following REST end points:
/products?product=xyz or /products?prodName=xyz or /products?prod=xyz
*

Resources