Use #XmlTransient only in some cases - java

I have two classes:
public class A implements Serializable {
...
#OneToMany(cascade = CascadeType.ALL, mappedBy = "fieldID")
private Collection<B> bCollection;
...
public Collection<B> getBCollection()
{
return bCollection;
}
public void setBCollection(Collection<B> bCollection)
{
this.bCollection = bCollection;
}
}
public class B implements Serializable {
...
#JoinColumn(name = "aID", referencedColumnName = "id")
#ManyToOne(optional = false)
private A aID;
...
#XmlTransient
public A getAID() {
return aID;
}
public void setAID(A aID) {
this.aID= aID;
}
}
I was always using A class - it is working as inteded, but now, I want to use B class in RESTful GET method. However, when I try to do that, #XmlTransient prevents showing A field. Is it possible to use #XmlTransient on A class, when I am using B class and to use it on B class, when I am using A class?

One easy solution is to include https://eclipse.org/eclipselink/moxy.php and start using #XmlInverseReference annotation for bi-directional dependencies. http://eclipse.org/eclipselink/api/2.2/org/eclipse/persistence/oxm/annotations/XmlInverseReference.html.
If it is not possible, please provide more information which JAXB/JAX-RS implementation you are using to be able to come up with some more concrete solution for your problem.
In general the idea is to control serialization process and decide how certain objects/fields are serialized and if those should be serialized at all. It can be achieved for example with following strategies:
Serialize class B not as a whole object, but rather just as a String representation of it, when class A is serialized. For example using #XmlAttribute #XmlIDREF.
Control serialization process by setting up, for example, some kind of Filter/Exclusion (depending on what does your JAX-RS implementation provide):
ExclusionStrategy() {
public boolean shouldSkipClass(Class<?> clazz) {
return (clazz == B.class);
}
/**
* Custom field exclusion goes here
*/
public boolean shouldSkipField(FieldAttributes f) {
return false;
}
}

Related

JPA MappedSuperClass common audit value for all entities

I have several JPA entities, each Entity has a database user column, in that column I have to store the user that makes changes to a specific row in the table.
I created a 'MappedSuperclass' Bean that all the entities would extend from, this is the MappedSuperclass.
#MappedSuperclass
public abstract class AuditableBean {
#Column(name = "modifier_user", nullable = false)
private String modifier_user;
// Getters and Setters
}
This is one Entity that extends from the 'MappedSuperclass'.
#Entity
#Table(name = "nm_area_ref")
public class ServingAreaReferenceBean extends AuditableBean {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "nm_area_ref_id")
private UUID id;
#Column(name = "nm_srv_area_desc", nullable = false)
private String description;
#Column(name = "nm_retired", nullable = false)
private boolean retired;
// Getters and Setters
}
And, all the Beans has a corresponding service method used to save the data on the database, this is one of the services class (each service injects a repository for CRUD operations).
// Service
#Component
public class ServingAreaReferenceBO {
#Inject private ServingAreaReferenceRepository repository; //repository injection
#Inject private CloudContextProvider cloudContextProvider;
public List<ServingAreaReferenceBean> getAllServingAreaReferences() {
return Lists.newArrayList(repository.findAll());
}
public Optional<ServingAreaReferenceBean> findById(UUID id) {
return repository.findById(id);
}
public ServingAreaReferenceBean create(ServingAreaReferenceBean servingAreaReference) {
Optional<CloudContext> cloudContext = Optional.ofNullable(cloudContextProvider.get());// line 1
servingAreaReference.setUpdaterUser(cloudContext.map(CloudContext::getUserId).orElse(null));// line 2
return repository.save(servingAreaReference);// line 3
}
}
// Repository - It extends from CrudRepository (insert, update, delete operations)
#Repository
public interface ServingAreaReferenceRepository extends CrudRepository<ServingAreaReferenceBean, UUID> {
boolean existsByDescription(String description);
boolean existsByDescriptionAndIdIsNot(String description, UUID id);
}
When 'repository.save()' (line 3) executes, It stores the user successfully, but I put the user logic just before executing the save method (lines 1, 2). So I don't think that repeating those two lines on each service would be the best approach, instead, I'd like to implement a generic method or a generic class that sets the user for all the Bean Entities before executing the save method.
Is that possible? what is the better approach for that?
I was thinking to implement something like this, but not sure how to make it generic?
#Component
public class AuditableBeanHandler {
#Inject private CloudContextProvider cloudContextProvider;
public AuditableBean populateAuditInformation(AuditableBean auditableBean) {
Optional<CloudContext> cloudContext = Optional.ofNullable(CloudContextProvider.get());
auditableBean.setUpdaterUser(CloudContext.map(cloudContext::getUserId).orElse(null));
return auditableBean;
}
}
Well what I understood, you have to set user before each save call of an entities :
This can be solved by using a well known design pattern called "Template method design pattern".
Just create a parent class for service class :
public abstract class AbstractService<T extends AuditableBean> {
public AuditableBean populateAuditInformation(AuditableBean auditableBean) {
Optional<CloudContext> cloudContext = Optional.ofNullable(CloudContextProvider.get());
auditableBean.setLastUpdatedByUser(CloudContext.map(cloudContext::getUserId).orElse(null));
return auditableBean;
}
public absract T save(T areaReference);
public final T create(T t) {
t = populateAuditInformation(t);
return save(t);
}
And in your service class extends this abstract service and add save method:
public class AreaReferenceService extends AbstractService<AreaReferenceBean> {
public AreaReferenceBean save(AreaReferenceBean AreaReference) {
return repository.save(AreaReference);
}
}
While calling service method, call create() method.
hope this will solve your problem, and also you can read more about Template method design pattern.
I think you're pretty close with the AuditableBean.
Add the following configuration to enable auditing:
// Annotate a configuration class with this
#EnableJpaAuditing(auditorAwareRef = "auditAware")
Add this "auditAware" bean, you'll want to tweak it to match whatever auth mechanism you're using. It's sole purpose is to return the username of the authenticated user, Spring will use this.
#Bean
public AuditorAware<String> auditAware() {
return () -> {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return Optional.of(authentication.getPrincipal());
};
}
Add one more annotation to your modified_user field (#LastModifiedBy). This tells Spring that when an update occurs on the entity, set this field to the value returned from your AuditAware bean.
#Column(name = "modifier_user", nullable = false)
#LastModifiedBy
private String modifier_user;
See the Spring Data JPA Documentation for more information on the available audit fields.

Updating only relevant entities in aggregates with #ColumnTransformer

In our spring boot application, I am trying to save an aggregate, that consists of a root entity (ParentEntity) and a Set of child entities (ChildEntity).
The intention is, that all operations are done through the aggreate. So there is no need for a repository for ChildEntity, as the ParentEntity is supposed to manage all save or update operations.
This is how the Entities look like:
#Entity
#Table(name = "tab_parent", schema = "test")
public class ParentEntity implements Serializable {
#Id
#Column(name = "parent_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer parentId;
#Column(name = "description")
private String description;
#Column(name = "created_datetime", updatable = false, nullable = false)
#ColumnTransformer(write = "COALESCE(?,CURRENT_TIMESTAMP)")
private OffsetDateTime created;
#Column(name = "last_modified_datetime", nullable = false)
#ColumnTransformer(write = "COALESCE(CURRENT_TIMESTAMP,?)")
private OffsetDateTime modified;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "ParentEntity")
private Set<ChildEntity> children;
// constructor and other getters and setters
public void setChildren(final Set<ChildEntity> children) {
this.children = new HashSet<>(children.size());
for (final ChildEntity child : children) {
this.addChild(child);
}
}
public ParentEntity addChild(final ChildEntity child) {
this.children.add(child);
child.setParent(this);
return this;
}
public ParentEntity removeChild(final ChildEntity child) {
this.children.add(child);
child.setParent(null);
return this;
}
}
#Entity
#DynamicUpdate
#Table(name = "tab_child", schema = "test")
public class ChildEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "child_id")
private Integer childId;
#Column(name = "language_id")
private String languageId;
#Column(name = "text")
private String text;
#Column(name = "created_datetime", updatable = false, nullable = false)
#ColumnTransformer(write = "COALESCE(?,CURRENT_TIMESTAMP)")
public OffsetDateTime created;
#Column(name = "last_modified_datetime", nullable = false)
#ColumnTransformer(write = "COALESCE(CURRENT_TIMESTAMP,?)")
public OffsetDateTime modified;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "parent_id", updatable = false)
private ParentEntity parent;
// constructor and other getters and setters
public ParentEntity getParent() {
return this.parent;
}
public void setParent(final ParentEntity parent) {
this.parent = parent;
}
}
This is the store method to save or update the entities:
public Integer merge(final ParentDomainObject parentDomainObject) {
final ParentEntity parentEntity =
this.mapper.toParentEntity(parentDomainObject);
final ParentEntity result = this.entityManager.merge(parentEntity);
this.entityManager.flush();
return result.getParentId();
}
And this is the store method to retrieve the aggregate by id:
public Optional<ParentDomainObject> findById(final Integer id) {
return this.repo.findById(id).map(this.mapper::toParentDomainObject);
}
As you can see our architecture strictly separates the store from the service layer. So the service only knows about domain objects and does not depend on Hibernate Entites at all.
When updating either the child or the parent, firstly the parent is loaded. In the service layer, the domain object is updated (fields are set, or a child is added/removed).
Then the merge method (see code snippet) of the store is called with the updated domain object.
This works, but not completely as we want to. Currently every update leads to the parent and EVERY chhild entity being saved, even if all field remained the same. We added the #DynamicUpdate annotaton. Now we saw, that the "modified" field is the problem.
We use a #ColumnTransformer to have the database set the date. Now even if you call the services update method without changing anything, Hibernate generates a update query for EVERY object, which updates only the modified field.
The worst thing about that is, as every object is saved, every modified date changed as well to the current date. But we need information about exactly which object really changed and when.
Is there any way to tell hibernate, that this column should not be taken into account when deciding what to update. However of course, if a field changed, the update operation should indeed update the modified field.
UPDATE:
My second approach after #Christian Beikov mentioned the use of #org.hibernate.annotations.Generated( GenerationTime.ALWAYS )
is the following:
Instead of #Generated (which uses #ValueGenerationType( generatedBy = GeneratedValueGeneration.class )),
I created my own annotations, which use custom AnnotationValueGeneration implementations:
#ValueGenerationType(generatedBy = CreatedTimestampGeneration.class)
#Retention(RetentionPolicy.RUNTIME)
public #interface InDbCreatedTimestamp {
}
public class CreatedTimestampGeneration
implements AnnotationValueGeneration<InDbCreatedTimestamp> {
#Override
public void initialize(final InDbCreatedTimestamp annotation, final Class<?> propertyType) {
}
#Override
public GenerationTiming getGenerationTiming() {
return GenerationTiming.INSERT;
}
#Override
public ValueGenerator<?> getValueGenerator() {
return null;
}
#Override
public boolean referenceColumnInSql() {
return true;
}
#Override
public String getDatabaseGeneratedReferencedColumnValue() {
return "current_timestamp";
}
}
#ValueGenerationType(generatedBy = ModifiedTimestampGeneration.class)
#Retention(RetentionPolicy.RUNTIME)
public #interface InDbModifiedTimestamp {
}
public class ModifiedTimestampGeneration
implements AnnotationValueGeneration<InDbModifiedTimestamp> {
#Override
public void initialize(final InDbModifiedTimestamp annotation, final Class<?> propertyType) {
}
#Override
public GenerationTiming getGenerationTiming() {
return GenerationTiming.ALWAYS;
}
#Override
public ValueGenerator<?> getValueGenerator() {
return null;
}
#Override
public boolean referenceColumnInSql() {
return true;
}
#Override
public String getDatabaseGeneratedReferencedColumnValue() {
return "current_timestamp";
}
}
I use these annotations in my entities instead of the #ColumnTransformer annotations now.
This works flawlessly when I insert a new ChildEntity via addChild(), as now not all timestamps of all entities of the aggregate are updated anymore. Only the timestamps of the new child are set now.
In other words, the InDbCreatedTimestamp works as it should.
Sadly, the InDbModifiedTimestamp does not. Because of GenerationTiming.ALWAYS, I expected the timestamp to be generated on db level, everytime an INSERT OR UPDATE is issued. If I change a field of a ChildEntity and then save the aggregate, an update statement is generated only for this one database row, as expected. However, the last_modified_datetime column is not updated, which is surprising.
It seems that this is unfortunately still an open bug. This issue describes my problem precisely: Link
Can someone provide a solution how to get this db function executed on update as well (without using db triggers)
You could try to use #org.hibernate.annotations.Generated( GenerationTime.ALWAYS ) on these fields and use a database trigger or default expression to create the value. This way, Hibernate will never write the field, but read it after insert/update.
Overall this has a few downsides though (need the trigger, need a select after insert/update), so I think this is a perfect use case for Blaze-Persistence Entity Views.
I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.
A DTO/domain model for your use case could look like the following with Blaze-Persistence Entity-Views:
#EntityView(ParentEntity.class)
#UpdatableEntityView
public interface ParentDomainObject {
#IdMapping
Integer getParentId();
OffsetDateTime getModified();
void setModified(OffsetDateTime modified);
String getDescription();
void setDescription(String description);
Set<ChildDomainObject> getChildren();
#PreUpdate
default preUpdate() {
setModified(OffsetDateTime.now());
}
#EntityView(ChildEntity.class)
#UpdatableEntityView
interface ChildDomainObject {
#IdMapping
Integer getChildId();
String getName();
}
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
ParentDomainObject a = entityViewManager.find(entityManager, ParentDomainObject.class, id);
The Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
Page<ParentDomainObject> findAll(Pageable pageable);
The best part is, it will only fetch the state that is actually necessary! It also supports writing/mapping back to the persistence model in an efficient manner. Since it does dirty tracking for you, it will only flush changes if the object is actually dirty.
public Integer merge(final ParentDomainObject parentDomainObject) {
this.entityViewManager.save(this.entityManager, parentDomainObject);
this.entityManager.flush();
return parentDomainObject.getParentId();
}

Parent-child relation between two objects causes JSON StackOverflowError

I am trying to achieve a parent-child relation between some objects and I ran into a bit of trouble.
In my case, I am trying to store objects within other objects (e.g. container stores multiple items or other containers with items). The tricky part is that every object in the storage should be able to tell what it's outermost parent object is. While this seems to work in my in-memory database (using h2 at the moment), trying to get a JSON representation of all my storage items gives this (I return a List<StorageUnit> ):
Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: java.util.ArrayList[0]->com.warehousing.storage.FixedContentsCase["contents"]->java.util.ArrayList[0]->com.warehousing.storage.FixedContentsCase["contents"]->...
Here are the classes:
StorageUnit
#Entity
#Inheritance
public abstract class StorageUnit {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#ManyToOne
private Location location;
protected Long parentContainerId;
// <getters & setters>
public abstract List<StorageUnit> getContents();
}
FixedContentCase
#Entity
public class FixedContentsCase extends StorageUnit {
#OneToMany
private List<Item> items;
public FixedContentsCase() {
super();
items = new ArrayList<>();
}
// <getters & setters>
#Override
public List<StorageUnit> getContents() {
// Return the case itself and its contents
List<StorageUnit> contents = new ArrayList<>(Arrays.asList(this));
for (StorageUnit item : items)
contents.addAll(item.getContents());
return contents;
}
}
Item
#Entity
public class Item extends StorageUnit {
private String description;
public Item() {
super();
this.description = "";
}
// <getters & setters>
#Override
public List<StorageUnit> getContents() {
return Arrays.asList(this);
}
}
I have tried to annotate the StorageUnit class with #JsonIgnoreProperties("parentContainerId") but it didn't work. Annotating parentContainerId with #JsonIgnore didn't help either. I also tried annotating the getters instead of the attributes themselves (as per following). Is there a way to work around this or is some kind of design change necessary? Thanks!
Using Jackson this is definitely possible by annotations like #JsonIgnore or the DTO approach BugsForBreakfast mentioned.
I created a jackson MixIn handler to allow dynamic filtering which i use to avoid the boilerplate of DTOs
https://github.com/Antibrumm/jackson-antpathfilter
The examples in the readme should show how it works and if it‘s a possible solution for you.
Your problem is that you add the storage unit itself to its list of contents, leading to infinite recursion if you traverse the tree downwards. The solution: Use a reference and only serialize the object once, using #JsonIdentityInfo and #JsonIdentityReference:
public class MyTest {
#Test
public void myTest() throws JsonProcessingException {
final FixedContentsCase fcc = new FixedContentsCase();
fcc.setId(Long.valueOf(1));
final Item item = new Item();
item.setId(Long.valueOf(2));
item.setDescription("item 1");
fcc.getItems().add(item);
final ObjectMapper om = new ObjectMapper();
System.out.println(om.writeValueAsString(fcc));
}
}
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
#JsonIdentityReference(alwaysAsId = false)
class Item extends StorageUnit {
...
}
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
#JsonIdentityReference(alwaysAsId = false)
class FixedContentsCase extends StorageUnit {
...
}
abstract class StorageUnit {
...
}

Is there a cleaner way of building a MappedSuperclass Tree class in Spring JPA?

I currently have several Entities that behave as a Tree and need to save them to the DB.
So in order to not have duplicated code for that I built this class:
#MappedSuperclass
public abstract class TreeStructure<T extends TreeStructure>
{
#ManyToOne(cascade = CascadeType.PERSIST)
private T parent;
#OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
protected Set<T> children = new HashSet<>();
/**
* Function that is used before deleting this entity. It joins this.children to this.parent and viceversa.
*/
#Transactional
#PreRemove
public void preDelete()
{
unregisterInParentsChildren();
while (!children.isEmpty())
{
children.iterator().next().setParent(parent);
}
}
public abstract long getId();
protected void setParent(T pParent)
{
unregisterInParentsChildren();
parent = pParent;
registerInParentsChildren();
}
/**
* Register this TreeStructure in the child list of its parent if it's not null.
*/
private void registerInParentsChildren()
{
getParent().ifPresent((pParent) -> pParent.children.add(this));
}
/**
* Unregister this TreeStructure in the child list of its parent if it's not null.
*/
private void unregisterInParentsChildren()
{
getParent().ifPresent((pParent) -> pParent.children.remove(this));
}
/**
* Move this TreeStructure to an new parent TreeStructure.
*
* #param pNewParent the new parent
*/
public void move(final T pNewParent)
{
if (pNewParent == null)
{
throw new IllegalArgumentException("New Parent required");
}
if (!isProperMoveTarget(pNewParent) /* detect circles... */)
{
throw new IllegalArgumentException(String.format("Unable to move Object %1$s to new Object Parent %2$s", getId(), pNewParent.getId()));
}
setParent(pNewParent);
}
private boolean isProperMoveTarget(TreeStructure pParent)
{
if (pParent == null)
{
return true;
}
if (pParent == this)
{
return false;
}
return isProperMoveTarget(pParent.parent);
}
public int getLevel()
{
return getParent().map(pParent -> pParent.getLevel() + 1).orElse(1);
}
/**
* Return the <strong>unmodifiable</strong> children of this TreeStructure.
*
* #return the child nodes.
*/
public Set<T> getChildren()
{
return Collections.unmodifiableSet(this.children);
}
public Optional<T> getParent()
{
return Optional.ofNullable(parent);
}
public Optional<Long> getParentCategoryId()
{
return parent == null ? Optional.empty() : Optional.of(parent.getId());
}
}
Then to actually implement it I simply do:
#Entity(name = "CATEGORY")
public class Category extends TreeStructure<Category>
{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#JsonProperty("category_id")
private long id;
// etc...
As far as I know, everything is working like a charm but everytime I get inside the TreeStructure class Intellij highlights some errors:
mappedBy = "parent" -> Cannot resolve attribute parent.
children.iterator().next().setParent(parent) -> Unchecked call to setParent(T) as a member of raw type TreeStructure
pParent.children.add(this) -> Unchecked call to add(E) as a member of raw type java.util.Set
I also tried not using generics so I could just have abstract TreeStructure and then extend from the other classes but then I have problems with parent/children since you can not refer a MappedSuperclass from OneToMany/ManyToOne references.
So, finally getting to the point: Is there anyway of implementing this in a better/cleaner way? Are this warnings meaningfull or it's just Intellij not being smarter enough?
The issue isn't with JPA, but with the use of generics.
First, change your abstract class signature so that it has a recursive type:
public abstract class TreeStructure<T extends TreeStructure<T>>
Next, you can't reference 'this' since you don't know the implementation of 'this' so you can either just cast it to 'T' or add an abstract method with a signature like this:
public abstract T getImpl();
And in the implementation just return 'this'.
public T getImpl() {
return this;
}
On a side node, its probably not a good idea to access the parent classes instance variables in your class. It would probably be a better idea to add an addChild and removeChild methods to you TreeStructure class.
I had a very similar scenario and i didn't use T. Instead i had only the abstract class because i didn't need the flexibility of typed children and i had no casts. it might ground you as far as I can see (shared code) but i don't know if you have other requirements.
Another difference in my case was the abstract class is not mapped superclass, but #Inheritance(strategy = InheritanceType.SINGLE_TABLE).
If it can help, you can find a complete working example in this repository
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class TreeStructure {
...
#ManyToOne(cascade = CascadeType.PERSIST)
private TreeStructure parent;
#OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
protected Set<TreeStructure> children = new HashSet<>();

spring serializes every attribute in class (lazy loading?)

I got issues with my model classes. For example:
#Entity
#Table(name = "kreis", catalog = "quanto_portal")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property="idKreis")
public class Kreis implements java.io.Serializable {
private Integer idKreis;
private String kreisname;
private Set<Ort> orts = new HashSet<Ort>(0);
public Kreis() {
}
public Kreis(String kreisname) {
this.kreisname = kreisname;
}
public Kreis(String kreisname, Set<Ort> orts) {
this.kreisname = kreisname;
this.orts = orts;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "idKreis", unique = true, nullable = false)
public Integer getIdKreis() {
return this.idKreis;
}
public void setIdKreis(Integer idKreis) {
this.idKreis = idKreis;
}
#Column(name = "kreisname", nullable = false, length = 50)
public String getKreisname() {
return this.kreisname;
}
public void setKreisname(String kreisname) {
this.kreisname = kreisname;
}
//#JsonManagedReference(value="kreis-ort")
#OneToMany(fetch = FetchType.LAZY, mappedBy = "kreis")
public Set<Ort> getOrts() {
return this.orts;
}
public void setOrts(Set<Ort> orts) {
this.orts = orts;
}
When I query for an "Kreis"-Object it also internally querys for the dependent "Orts", although Lazy-Loading is set. Next, in "Ort"-class a statement for dependent "Kreis"-objects is done (cause it's an attribute of Ort; Lazy-Loading is set). If "Ort" has more dependent classes/attributes for example "Persons", even the whole "Person"-class is loaded. Can anyone tell me why? Do I need to set a property in Spring or initializing a specific bean?
So far I need to ignore (with #JsonIgnoreProperties) every attribute that references to another class. I think thats wrong, cause lazy-loading should effect that dependet objects are only loaded, if I ask for it.
LAZY means lazily loaded from the database when the collection is accessed. As soon as Jackson starts serializing the object, it reads all the fields, including the orts field, which triggers the lazy loading.
If you're wanting to only serialize certain fields, then you probably want to return a projection of some sort from your controller; the just-released Spring Data Hopper M1 supports returning projections from Spring Data repositories, and you can also use Jackson projections if you need to deal with the full entity object in your controller.

Categories