We are using MapStruct with Spring Data to convert between JPA entities and DTO classes. All the mappers follow the same pattern with methods beanToDTO() and dtoToBean(). After a learning cure, we have all this working. Now we are trying to use Spring injection to replace the implementation on JPA entity, DTO, and Mapper classes. We have the JPA entities and DTO replacement working. So now we are trying to have Spring inject alternative Mapper implementation.
For our problem, we can subclass the mapper interface and not it will have 2 beanToDTO() methods and 2 dtoToBean methods(), 1 for the base JPA entity and DTO and 1 for the subclassed JPA entity and DTO. This works fine for straightforward examples.
For mappers that require some customization, we utilize the #Mapping annotation and #InheritInverseConfiguration for the base mapper. For the subclassed mapper, we try the same thing but the problem is the InheritInverseConfiguration in the subclass mapper gives the error "Several matching inverse methods exist: beanToDTO(), beanToDTO(). Specify a name explicitly."
Both methods have the same name so we have no way to identify the implementation we want to reference. I realize that the problem is due to our implementation approach but it simplifies our code to:
- getBean()
- getMapper().beanToDTO()
and we will be able to replace JPA entity, Mapper , and DTO via Spring injection.
Are there other MapStruct trick that will help us with this problem?
Thanks
Have you looked at the #MapperConfig.. checkout our unit test. I would advise to put your base / prototype methods in #MapperConfig annotated shared configuration interface that you can reference in #Mapper
See this unit test for more info. Or checkout the user guide.
Related
I am new to EF.
Is it possible to inject entities in an EF context?
Taking the case from Microsoft documentation: https://learn.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext
Let's say, I have different implementations of blog. When it comes to properties that require persistence, they are the same and implement IBlog interface to reflect that.
How should I define BloggingContext to work with any of the blogs? I cannot use IBlog. DBSet would not accept an interface as a generic reference type to be used as entity type.
Do I have do define a base abstract class for my blogs in order to inject them in EF context? Is this the only way?
I want to avoid using proprietary Jackson annotations on my JPA entities, but need to serialize them. If I do, I will run into an exception because my a parent is referenced through the child causing a cycle.
Are there any alternatives to marking up my entities, could Jackson be configured to look at the JPA annotations and ignore ones with a mappedBy property? Or is there another way to achieve this?
I don't know any ways to directly ask Jackson to ignore the the recursive without annotations. But if you want to force him to ignore any fields with a special annotation you could write some custom serializer in addition of reflection to avoid them.
http://static.javadoc.io/com.fasterxml.jackson.core/jackson-databind/2.9.1/com/fasterxml/jackson/databind/JsonSerializer.html
Reading about using Java Generics in DAO layer, I have a doubt applying this in spring data repositories. I mean, with spring data repositories, you have something like this:
public interface OrderRepository extends CrudRepository<Order,OrderPK>{
}
But if I have other 10 entities, I have to create 10 interfaces like the one above to execute CRUD operations and so on and I think this is not very scalable. Java Generics and DAO is about creating one interface and one implementation and reuse this for entities but with Spring Data repositories I have to create one interface for each entity so ...
You didn't really state a question, so I just add
Is this really true? And if so, why?
and answer it:
Yes, this is (almost) correct. Almost, because you should not create one repository per entity, but one repository per Aggregate Root. See http://static.olivergierke.de/lectures/ddd-and-spring/
Spring Data Repositories offer various features for which Spring Data needs to know, what entity it is dealing with. For example query methods need to know the properties of the entity, in order to convert the method name to JPA based query. So you have to pass in the information to Spring Data at some point and you also have to pass in the information, which entities should be considered Aggregate Roots. The way you do that, is by specifying the interface.
Do you really need that? Well if all you want is generic Crud functionality, you can get that straight out of the box with JPA. But if you want query methods, Pagination, simple native queries and much more Spring Data is a nice way to avoid lots of boiler-plate code.
(Please keep in mind that I'm biased)
I want to add JPA criteria api queries in repository which I have defined in my spring data rest demo. And then expose those queries using GET. Till now, I have not discovered, how to do the same. If anyone has done the same, any light on the same/ Sample code shall be much appreciated.
Thanks
Assuming you followed the conventions for custom methods all the custom methods are exposed as
[BASE_URI]/search/[CUSTOM_METHODS]
. Also there are little more constraints on these custom methods to exposed like all parameters to custom methods must be annotated with #Param. Optionally custom methods could return Page<?>, List<?> object and also can accept Pageable and Sort type params.
I am wondering what is the best way to handle mapping of entity beans (JPA 2) to DTOs.
Since you cannot use entity beans "directly" with GWT, you need to handle DTOs instead.
I have several entities with various relationships (OneToOne, OneToMany, ManyToMany with a join table etc).
Initially i started converting all entities to DTOs by hand with the help of a class MyEntityTransform.java with methods like :
static final public CarBean persistant2Bean(CarPersist) {
return new CarBean(cartPersist.getId(), carPersist.getName(),
carPersist.getDescription());
}
Other methods are : persistent2BeanCollection(...), persistent2BeanMap(...), bean2Persistent(...), bean2PersistentCollection(...)
That becomes a fastidious task when handling collections, especially when the same entity has references to several other entities;
I have been thinking about using the DOZER framework to handle the mapping between entities and DTOs.
It is mentionned here : http://code.google.com/intl/fr/webtoolkit/articles/using_gwt_with_hibernate.html
However i am not sure how well it handles the various JPA mappings (manytomany for instance) and how much work it is to configure it in the dozer-bean-mappings.xml file.
Also i guess this framework is intensively using reflection to perform mapping operations. Such approach is much slower than mapping performed "by hands", e.g. when i use the methods in my MyEntityTransform.java class.
What do you suggest ? i'm interested in everybody's experience handling JPA entities with GWT.
Thanks.
Celinio
http://www.celinio.net/techblog
In first instance I would always prefer Dozer. When the DTO structure is the same as your entities, you can use Dozer with zero configuration by simply calling the map function. When your DTOs differ from your entities the configuration overhead is minimal. Simply look in the really good documentation.
When performance becomes an issue, I would prefer a code generator approach, but I would never write the mapping code by myself cause it can be very error prone.
If you want to just include entities in you EJB or JPA module in your GWT module follow these steps. I found it out my own and It worked for me.
Include your EJB module in GWT module's build path (you may have already done that)
Now goto your entities package in EJB module (i will take it as "com.ejbproject.entities")
Create a file named Entities.gwt.xml (<ProjectSourcePath>/com/ejbproject/entities/Entities.gwt.xml)
File content should be
<module>
<source>com.ejbproject.entities</source>
</module>
Now include following fragment in your GWT project's <modulename>.gwt.xml file.
<inherits name="com.ejbproject.entities.Entities"/>
Now you can include Entities in your GWT client side and gwtCompile without any problem