Model Mapper - using custom methods - java

A springboot project where I need to construct a DTO for a dashboard view using nominated fields from the parent and nominated fields from the newest of each of the children.
The entities are Plane which has a OneToMany relationship with Transponder, Maint Check and Transmitter.
Plane
#Entity
#Data
public class Plane {
#Id
#GeneratedValue(strategy = IDENTITY)
private Long id;
private String registration;
#JsonIgnore
#OneToMany(cascade = CascadeType.ALL, mappedBy = "plane")
private List<Transponder> listTransponder = new ArrayList<>();
#JsonIgnore
#OneToMany(cascade = CascadeType.ALL, mappedBy = "plane")
private List<Transmitter> listTransmitter = new ArrayList<>();
#JsonIgnore
#OneToMany(cascade = CascadeType.ALL, mappedBy = "plane")
private List<MaintCheck> listMaintCheck = new ArrayList<>();
Transponder
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
public class Transponder {
#Id
#GeneratedValue(strategy = IDENTITY)
private Long id;
private String code;
private LocalDate dateInserted;
#ManyToOne(fetch = FetchType.LAZY, optional = true)
private Plane plane;
}
Maint Check and Transmitter have similar entities with a LocalDate field.
PlaneDTO looks liike
#Data
public class PlaneDTO {
private String registration;
private LocalDate maintCheck; // date of most recent Maint Check
private String transponderCode; // string of most recent Transponder code
private Integer channel; // Intger of most recent Transmitter Freq
}
I have attempted to consruct this PlaneDTO in the service layer, but I am manually doing much of the sorting of the lists of Transponder, Transmitter and Maint Check to get the most recent record from these lists.
//DRAFT METHOD CONSTRUCT DTO
#Override
public PlaneSummaryDTO getPlaneSummaryDTOById(Long id) {
Plane Plane = this.get(id);
PlaneSummaryDTO PlaneSummaryDTO = new PlaneSummaryDTO();
ModelMapper mapper = new ModelMapper();
PlaneSummaryDTO = modelMapper.map(get(id), PlaneSummaryDTO.class);
PlaneSummaryDTO.setTRANSPONDERCode(getNewestTRANSPONDERCode(Plane));
PlaneSummaryDTO.setLastMaintCheck(getNewestMaintCheckDate(Plane));
PlaneSummaryDTO.setChannel(getTransmitterCode(Plane));
PlaneSummaryDTO.setChannelOffset(getTransmitterOffset(Plane));
return PlaneSummaryDTO;
}
// RETURN NEWEST DATE OF MAINT CHECK BY CATCH DATE
public LocalDate getNewestMaintCheckDate(Plane Plane) {
List<MaintCheck> listMaintCheck = new ArrayList<>(Plane.getListMaintCheck());
MaintCheck newest = listMaintCheck.stream().max(Comparator.comparing(MaintCheck::getCatchDate)).get();
return newest.getCatchDate();
}
// RETURN NEWEST TRANSPONDER CODE FROM Plane BY DATE INSERTED
public String getNewestTransponderCode(Plane Plane) {
List<Transponder> listTransponder = new ArrayList<>(Plane.getListTransponder());
Transponder newest = listTransponder.stream().max(Comparator.comparing(Transponder::getDateInserted)).get();
return newest.getCode();
}
// OTHER METHODS TO GET MOST RECENT RECORD
QUESTION Is there a better way to calculate the most recent record of the child, using model mapper more efficiently (custom method?)
I am open to changing to MapStruct if it better supports getting the most recent child.

I briefly used ModelMapper in the past. I would suggest using mapstruct since I personaly find it easier to use. I know your mapping can be done there ;). In Mapstruct your Mapper could look something like this:
#MapperConfig(
componentModel = "spring",
builder = #Builder(disableBuilder = true)
)
public interface PlaneMapper {
#Mapping(target = "lastMaintCheck", ignore = true)
PlaneDTO planeToPlaneDTO(Plane plane);
#AfterMapping
default void customCodePlaneMapping(Plane source, #MappingTarget PlaneDTO target) {
target.setLastMaintCheck(source.getListMaintCheck.stream().max(Comparator.comparing(Transponder::getDateInserted)).get())
}
Your mapper call would then only be one line:
#Service
#RequiuredArgsConstructor
public class someService{
private final PlaneMapper planeMapper;
public void someMethod(){
....
PlaneDTO yourMappedPlaneDTO = planeMapper.planeToPlaneDTO(plane);
....
}
I did not fill in all values. But i hope the concept is clear.
EDIT:
You would also have to add the dependency of "mapstruct-processor" so that the MapperImpl classes can be gererated.
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>

So here's a different approach to the data model. I'll be using Transponder because the others are analog.
The target domain model could look like this:
#Data
class Plane {
Long id;
String registration;
Transponder activeTransponder;
}
#Data
class Transponder {
Long id;
Integer code; // this is a 4-digit octal number, why String? your call though
Long planeId;
Instant assignStart;
Instant assignEnd;
}
In the database, it would be sufficient to store the id and registration for the plane, because you can determine the current transponder with a proper query on the db entity, eg where transponder.planeId=id and transponder.assignEnd IS NULL. You can also store the transponderId of course, but then you'd need to take care to keep the data consistent between the tables.
If you want a history of all transponders - which to me seems like an entirely different use case to me, you can easily retrieve it in a separate service with a query getTransponderHistoryByPlane(long planeId) with a query like from transponders t where t.planeId=$planeId sorted by t.assignStart.
Again, this does depend on your use cases, and assumes that you usually only need one transponder for a given plane except in special cases, like from a different endpoint.
Anyway, this were my thoughts on the domain model, and you were aiming for your Dto; however, this is then easily mapped with mapstruct like (assuming you do the same for maintCheck and transmitter)
#Mapper
interface PlaneDtoMapper {
#Mapping(target = "transponderCode", source = "transponder.code")
#Mapping(target = "maintCheck", source = "maintCheck.date")
#Mapping(target = "channel", source = "transmitter.channel")
PlaneDTO fromPlane(Plane p);
}
You don't need the "registration" mapping because the fields in plane and dto are the same, and the #Mapping annotations tell mapstruct which subfields of which fields of plane to use.

Related

MapStruct cannot find members from generic Set property

I started using MapStruct 1.4.0.CR1. I'm also using Gradle:
dependencies {
annotationProcessor("org.mapstruct:mapstruct-processor:${project.property("mapstruct.version")}")
implementation("org.mapstruct:mapstruct:${project.property("mapstruct.version")}")
}
I have some JPA entities I'm trying to map:
public class Exam implements Serializable {
// More class members here
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "exam", orphanRemoval = true)
private Set<Scan> scans;
public Exam() { } // ...no-argument constructor required by JPA
public Exam(final Builder builder) {
// ...set the rest also
scans = builder.scans;
}
// getters (no setters), hashCode, equals, and builder here
}
public class Scan implements Serializable {
// More class members here
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "scan", orphanRemoval = true)
private Set<Alarm> alarms;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "scan", orphanRemoval = true)
private Set<Isotope> isotopes;
protected Scan() { } // ...no-argument constructor required by JPA
public Scan(final Builder builder) {
// ...set the rest also
alarms = builder.alarms;
isotopes = builder.isotopes;
}
// getters (no setters), hashCode, equals, and builder here
}
I have similar classes for mapping, but they don't have as many fields/members as the JPA entities, moreover, they are on a completely different sub-system (hence the mapping). The problem is that MapStruct is telling me there are no isotopes within Scans: java: No property named "scans.isotopes" exists in source parameter(s). Did you mean "scans.empty"?.
Basically, isotopes and alarms are not contained within a Set of scans in the (new) mapped Exam class. This is my ExamMapper:
#FunctionalInterface
#Mapper(componentModel = "spring", injectionStrategy = InjectionStrategy.CONSTRUCTOR)
public interface ExamMapper {
// #Mapping(source = "scans.alarms", target = "alarms")
#Mapping(source = "scans.isotopes", target = "isotopes")
Exam valueFrom(tld.domain.Exam entity);
}
Is there a way to accomplish this? I think this may be trivial, but I'm fairly new to MapStruct ;)
The source and target attributes of the #Mapping can only reference bean properties.
This means that when using scans.isotopes, it will look for a property isotopes in Set<Scan> and thus the compile error.
In order to solve this you'll need to provide some custom mappings. From what I can understand you will need to do flat mapping here as well. The reason for that is that you have multiple scans, and each scan has multiple isotopes. You need to gather all of that and map it into a single collection.
One way to achieve this is in the following way:
#Mapper(componentModel = "spring", injectionStrategy = InjectionStrategy.CONSTRUCTOR)
public interface ExamMapper {
#Mapping(source = "scans", target = "isotopes")
Exam valueFrom(tld.domain.Exam entity);
Isotope valueFrom(tld.domain.Isotope isotope);
default Set<Isotope> flatMapIsotopes(Set<Scan> scans) {
return scans.stream()
.flatMap(scan -> scan.getIsotopes().stream())
.map(this::valueFrom)
.collect(Collectors.toSet());
}
}

Java JPA Mapping Problem with nested Collections

I have the following problem: I have three connected classes. I have annotated them but I am getting wrong results (described below):
#Entityd
#Table(name = "ClassA")
public class ClassA{
#Id
#GeneratedValue
private Long id = 0L;
...
#OneToMany(fetch = FetchType.EAGER,cascade=CascadeType.ALL)
#Fetch(FetchMode.SELECT)
#Column(name = "ClassBList")
private List<ClassB> listB;
...
}
#Entity
#Table(name="ClassB")
public class ClassB {
#Id
#GeneratedValue
private Long id = 0L;
...
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#Fetch(FetchMode.SELECT)
#Column(name = "ClassCList")
private List<ClassC> listC;
...
}
#Entity
#Table(name="ClassC")
public class ClassC {
#Id
#GeneratedValue()
private Long id = 0L;
...
#ElementCollection
private List<String> listD;
...
}
When I work with this structure for the first ClassA I create,save and load everything is ok. For a new instance of ClassA which I save to repo and load again, I suddenly have the strings of the first ClassA in listD.
The result I need is that every class is "independently" saved. So the collections of each class should hold unique (each one with its own id and sublists) objects.
What would be the best way (annotations) to model this classes in Java 8 with Spring Boot 2.2.0.M5 and javax.persistence-api 2.2 ?
EDIT:
I have now removed class B and rewrote classA to:
#Entity
#Table(name = "ClassA")
public class ClassA{
#Id
#GeneratedValue
private Long id = 0L;
...
#OneToMany(fetch = FetchType.LAZY, orphanRemoval = true, cascade = CascadeType.ALL)
#MapKey(name = "type")
private Map<String,Set<ClassC>> classCmap;
...
}
This is giving me an error like:
org.hibernate.AnnotationException: Use of #OneToMany or #ManyToMany targeting an unmapped class
How can I model/solve/annotate this?
If you don't need to query data based on listD, I would suggest to keep the list as text in the database and use a converter:
#Converter
public class ListDConverter implements AttributeConverter<List<String>, String> {
private ObjectMapper objectMapper = new ObjectMapper();
#Override
public String convertToDatabaseColumn(List<String> listD) {
try {
return objectMapper.writeValueAsString(listD);
} catch(IOException e){
return null;
}
}
#Override
public List<String> convertToEntityAttribute(String stringListD) {
if(stringListD == null){
return Collections.emptyList();
}
try {
return objectMapper.readValue(stringListD, new TypeReference<List<String>>() {});
}catch(IOException e){
return Collections.emptyList();
}
}
}
and in your ClassC entity class :
#Convert(converter = ListDConverter.class)
private List<String> listD;
Why do I like this approach :
No extra table and joins => better performance
Easier to read listD in the database
#ElementCollection describes a table. So your code is probably creating a "listD" table with one column of type string, with no primary key.
Also, do you really want to use the SELECT fetch mode? That's going to generate 1 + b + b*c queries when you could just implement your data as sets (since you have unique identifiers) and use JOIN, which would result in one and only one query.
See this site for an explanation on how to use #ElementCollection.

How to prevent model mapper from eager loading associated collections in spring data jpa?

How to prevent model mapper from eager loading associated collections in spring data jpa ?
Ugh I had this issue last time and I must say that this is the point I start to not like ModelMapper :)
Basically the only way to do this is to define your own TypeMap with proper mappings that will ommit the collection mapping. The problem is if you have fetched Entity instance and sometimes you want to map it to the target class with collections and sometimes not (depends on whether collection was fetched or not).
This causes the situation when you should check whether the Collection field is fetched using some weird mechanisms like checking LazyInitializationException or the type of proxy implementation properties of the field if you are using Hibernate... madness
What I suggest is to create a few types of target Model class with or without the collection field, and for each of them custom mappings configuration (if your application design allows it) or to not using ModelMapper at all in case of this specific entity (and just provide your own mapping mechanism)
I was facing this issue where I had a User entity with a One-to-Many mapping to Role, i.e. one user has many roles
#Entity
#Table(name = "user")
public class User implements Serializable {
#Id
#Basic(optional = false)
#Column(name = "id")
private String id;
#Basic(optional = false)
#Column(name = "name")
private String name;
#Basic(optional = false)
#Column(name = "email_id")
private String emailId;
.............
#OneToMany(cascade = CascadeType.ALL, mappedBy = "user")
private Collection<UserRole> userRoleCollection;
}
I wanted to map this class to a DTO
#Data
public class UserVO implements Serializable {
/**
*
*/
private static final long serialVersionUID = -7985084979805425972L;
private String name;
private String emailId;
......
private List<RoleVO> roles;
}
Basically I needed to convert Collection<UserRole> to List<RoleVO> using ModelMapper, where Collection<UserRole> was lazy-loaded.
I setup a ModelMapper Converter as follows:
#Configuration
public class ModelMapperConfiguration {
public ModelMapper modelMapper() {
ModelMapper mapper = new ModelMapper();
TypeMap<User, UserVO> userToUserVOTypeMap = mapper.createTypeMap(User.class, UserVO.class);
TypeMap<Role, RoleVO> roleRoleVOTypeMap = mapper.createTypeMap(Role.class, RoleVO.class);
Converter<Collection<UserRole>, List<RoleVO>> collectionListConverter =
ctx -> (ctx == null) ? null : ctx.getSource().stream()
.map(ur -> roleRoleVOTypeMap.map(ur.getRole()))
.collect(Collectors.toList());
userToUserVOTypeMap.addMappings(mpr ->
mpr.using(collectionListConverter)
.map(src -> src.getUserRoleCollection(), UserVO::setRoles));
}
}
The stream() method should trigger a FETCH for lazy-loaded data.

Jackson #JsonView for long chain of associations on JPA/Hibernate entity graph

I have the following code:
public interface JSONInvoiceView {
public interface JSONInvoiceBasicView {
}
public interface JSONInvoiceWithLinesView extends JSONInvoiceBasicView {
}
}
#PersistenceUnit(unitName="ERP_PU")
#Entity
#Table(name="INVOICE")
public class Invoice extends FrameworkEntity {
#Id
#SequenceGenerator(name = "PK_INVOICE_GEN", sequenceName = "PK_INVOICE_GEN", allocationSize=1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "PK_INVOICE_GEN")
#Column(name = "ID")
#JsonView(JSONInvoiceView.JSONInvoiceBasicView.class)
private Long id;
#OneToMany(mappedBy="invoiceLine", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JsonView(JSONInvoiceView.JSONInvoiceWithLinesView.class)
#JsonManagedReference
private List<InvoiceLine> lines = new ArrayList<InvoiceLine>();
#Temporal(TemporalType.DATE)
#Column(name = "DATE")
#JsonView(JSONInvoiceView.JSONInvoiceBasicView.class)
private Date startDate;
//...
}
#PersistenceUnit(unitName="ERP_PU")
#Entity
#Table(name="INVOICE_LINE")
public class InvoiceLine extends FrameworkEntity {
#Id
#Column(name = "ID")
#JsonView(JSONInvoiceView.JSONInvoiceWithLinesView.class)
private Long id;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
#JoinColumn(name="FK_INVOICE")
#JsonBackReference
private Invoice invoice;
#Column(name = "AMOUNT")
#JsonView(JSONInvoiceView.JSONInvoiceWithLinesView.class)
private BigDecimal amount;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
#JoinColumn(name="FK_GOOD")
private Good good;
//...
}
#PersistenceUnit(unitName="ERP_PU")
#Entity
#Table(name="GOOD")
public class Good extends FrameworkEntity {
#Id
#Column(name = "ID")
private Long id;
#Column(name = "DESCRIPTION", length=200)
private String description;
//...
}
So – one Invoice can have multiple InvoiceLines and each line has reference to Good. I need to get two JSON views: Inovice-only view and Invoice+InvoiceLine-only view. My domain is far richer than these 3 classes – the whole entity graph involves tens of classes and I need careful control how much of this graph I am loading in my entities. But I need to control also how much of loaded graph the JSON serialization facility should try to serialize. And I have the problem with this second control.
entityList is list of Invoices which has loaded InvoiceLines (with touch, e.g. invoiceLines.size();) but InvoiceLines have not further loaded Goods (invoiceLine.good is not touched during lazy load). So, entityList if Invoice+InvoiceLines.
I use the following code for Invoice-only view and this code works:
jsonString = objectMapper.writerWithView(JSONInvoiceView.JSONInvoiceBasicView.class).writeValueAsString(entityList);
Code for retrieving JSON view with Invoice+InvoiceLine-only data:
jsonString = objectMapper.writerWithView(JSONInvoiceView.JSONInvoiceWithLinesView.class).writeValueAsString(entityList);
And this code does not work, it raises error message:
org.codehaus.jackson.map.JsonMappingException: could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->mycom.entities.Invoice["invoiceLines"]->org.hibernate.collection.internal.PersistentBag[0]-> mycom.entities.Good["good"]-> mycom.entities.Good_$$_jvst4f9_c["id"])
at org.codehaus.jackson.map.JsonMappingException.wrapWithPath(JsonMappingException.java:218)
at org.codehaus.jackson.map.JsonMappingException.wrapWithPath(JsonMappingException.java:183)
at org.codehaus.jackson.map.ser.std.SerializerBase.wrapAndThrow(SerializerBase.java:140)
at org.codehaus.jackson.map.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:158)
at org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:112)
Caused by: org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:165)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:286)
So, the question is – what Jackson views/annotations should I apply to serialized Invoice+InvoiceLine only parts of entity graph which has loaded only Invoice+InvoiceLine data? How should I indicate that Jackson should not try to go further along association chain and Jackson should not try to serialize 3rd, 4th and so order associations, Jackson should not try to serialize good entities?
p.s. Ignore annotations (or any similar global annotation on entities) is not applicable in my case, because there will be cases when I need only Invoice data and then there will be cases when I will need Invoice+InvoiceLine+Good data and further I will need data Invoice+InvoiceLine+Good+GoodSupplier, etc.
I have found solution - Jackson perceives fields without #JsonView annotation as the fields belonging to every view. Therefor I should introduce additional view:
public interface JSONInvoiceView {
public interface JSONInvoiceBasicView {
}
public interface JSONInvoiceWithLinesView extends JSONInvoiceBasicView {
}
public interface JSONInvoiceWithLinesViewExt extends JSONInvoiceWithLinesView {
}
}
And apply new interace to the Good field:
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
#JoinColumn(name="FK_GOOD")
#JsonView(JSONInvoiceView.JSONInvoiceWithLinesExtView.class)
private Good good;
So - I should define new JSON view interfeice for each level of associations for my entities. After appling #JsonView all works like a charm.

jackson - do not serialize lazy objects

I have an entity:
#Entity
public class Book {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column
private String title;
#OneToMany(fetch = FetchType.LAZY, mappedBy = ("movie"),cascade = CascadeType.ALL)
private List<Genre> genre;
}
Then I have a controller whose purpose is to retrieve books, my problem is that, the genre field is being included in the json response of my controller. Any way I can exclude those fields that are lazy loaded when jackson serializes the object?
This is the configuration of my ObjectMapper:
Hibernate4Module hm = new Hibernate4Module();
hm.configure(Hibernate4Module.Feature.FORCE_LAZY_LOADING, false);
registerModule(hm);
configure(SerializationFeature.INDENT_OUTPUT, true);
Thanks!
I can't mark it as JsonIgnore, as it will be forever out of the serialization box. There will be times where I will need to retrieve the genres along with the book, and by then I will use "fetch join" on my query so it will not be null.
You can do this with the Jackson #JsonInclude annotation.
According to the latest version's javadoc (2.4 right now) you can specify with a simple annotation if to include or not the annotated property if the field value is null or empty.
By default, it's JsonInclude.Include.ALWAYS, and this means that even if your lazily not-loaded values are null, Jackson does include the property.
Specifying to don't include empty or null values can significantly reduce the size of the JSON response, with all the benefits included..
If you want to change this behavior, you can add the annotation at class-level or single property/getterMethod level.
Try to add the following annotations to the fields you don't want to include if empty:
#JsonInclude(JsonInclude.Include.NON_EMPTY)
#OneToMany(fetch = FetchType.LAZY, mappedBy = ("movie"),cascade = CascadeType.ALL)
private List<Genre> genre;
You can use a spring configuration to disable force lazy loading by default!
#Configuration
public class JacksonConfig {
#Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
Hibernate5Module hibernate5Module = new Hibernate5Module();
hibernate5Module.configure(Feature.FORCE_LAZY_LOADING, false);
// Enable below line to switch lazy loaded json from null to a blank object!
//hibernate5Module.configure(Feature.SERIALIZE_IDENTIFIER_FOR_LAZY_NOT_LOADED_OBJECTS, true);
mapper.registerModule(hibernate5Module);
return mapper;
}
}
You can use Jackson's JSON Filter Feature:
#Entity
#JsonFilter("Book")
public class Book {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column
private String title;
#OneToMany(fetch = FetchType.LAZY, mappedBy = ("movie"),cascade = CascadeType.ALL)
private List<Genre> genre;
}
#Entity
#JsonFilter("Genre")
public class Genre {
...
}
Then in the Controller you specify what to filter:
#Controller
public class BookController {
#Autowired
private ObjectMapper objectMapper;
#Autowird
private BookRepository bookRepository;
#RequestMapping(value = "/book", method = RequestMethod.GET, produces = "application/json")
#ResponseBody
public ResponseEntity<String> getBooks() {
final List<Book> books = booksRepository.findAll();
final SimpleFilterProvider filter = new SimpleFilterProvider();
filter.addFilter("Book", SimpleBeanPropertyFilter.serializeAllExcept("genre");
return new ResponseEntity<>(objectMapper.writer(filter).writeValueAsString(books), HttpStatus.OK)
}
}
In this way, you can control when you want to filter the lazy relation at runtime
Maybe this is related to a known issue about lazy loading.
I don't use jackson-datatype-hibernate, but what I've done to solve the same problem is to get the persistent collection out of the picture by using a DTO instead of serializing a Hibernate object directly. Tools like Dozer can help you out with that. Alternatively, there's a small utility I wrote to do mappings like this.
If you just want to experiment with what a DTO could look like, you can replace the unloaded persistent collection with a regular empty collection, like books.setGenre(new ArrayList<>()); Unfortunately I don't know of a way to tell if a lazily loaded object has been loaded or not, so you can't do this reassignment automatically. The places where you replace persistent collections would need to be determined by you on a case by case basis.
You can use Gson instead of ObjectMapper and while defining the entity mark the field as "transient"
public class Book {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column
private String title;
#OneToMany(fetch = FetchType.LAZY, mappedBy = ("movie"),cascade = CascadeType.ALL)
private **transient** List<Genre> genre;
}
while Deserialization using gson.toJson(book) , Gson will not deserialize that element.

Categories

Resources