I have hibernate pojo class which has a ManytoOne relation with another class.
class Employee {
#OneToMany
private String id;
}
class ITEmployee {
private Employee employee;
#ManyToOne
#JoinColumn(name="EMPLOYEE_ID)
public Emplyee getEmployee() {
return employee;
}
}
Now when I retrieve a row and marshall to a JSON/XML REST response, I get nested object of Employee class and ITEmployee class within each object.
Like eg,
{"ITEmployee":[{"id":1234,"Employee":[{"id":222, "ITEmployee":{"id":1234,"Employee":[{"id":222, "Employee":[{"id":222, "ITEmployee": . .. .
and so on.
How can I ignore the ManytoOne relation while marshalling?
I don't want to create another class and map them seperately.
I tried using #JsonIgnore and #Transient but that didn't work.
REST API : JAX-RS
Cheers!!
You can tell Jackson to not marshall some fields.
You have multiple choices. The simpliest is to use #JsonIgnore annotation on your employee Field.
If you want more advanced features, you can check for #JsonView.
EDIT : I see you already tried to use #JsonIgnore. Can you paste your code ? In principe it must work.
Related
In my Spring boot apps, I use a custom class for mapping from entity to dto or vice versa. On the other hand, I know there are some better options e.g. ModelMapper or Converter class.
After my searches, I have seen some good examples as shown below:
Automatically Mapping DTO to Entity on Spring Boot APIs
It sounds good, but as I have no previous experience, I wanted to be clarified about some points before proceeding. Could you help me please?
1. Is that solution is a proper ModelMapper example and can I also apply that approach for mapping entity to DTO?
2. What about implementing Converter interface without using a 3rd party library? Can I also build a generic mechanism using Converter interface?
Note: I also considered using MapStruct or JMapper, but ModelMapper sounds easier to use and for this reason I decided to use ModelMapper. But if you have some suggestion that clearly shows one of them has more advantegous, feel free to share your suggestions. I could also consider to use it.
Any help would be appreciated.
From my expérience, this is my suggestion. You have 1 entity and 1 entityDTO.
You make a constructor of entity that takes in parameter the entity DTO. Then you make a constructor for entityDTO that takes in parameter an entity.
Finnaly, you create a mapper class for a given element that will use the 2 constructors to generate what you need. Here is an exemple :
Entity.java :
#Entity
#Getter
#Setter
#NoArgsConstructor
#Table(name="entity")
public class Entity{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id_entity;
#Column(name = "name")
private String name;
public Entity(EntityDTO entityDTO){
this.setId_entity(entityDTO.getId_entity())
this.setName(entityDTO.getName())
}
}
EntityDTO.java :
#Getter
#Setter
#NoArgsConstructor
public class EntityDTO{
private Long id_entity;
private String name;
public EntityDTO(Entity entity){
this.setId_Entity(entity.getId_entity())
this.setName(entity.getName())
}
}
EntityMapper.java :
#Component
public class EntityMapper{
public EntityDTO toDto(Entity entity){
return new EntityDTO(entity);
}
public Entity toEntity(EntityDTO entityDTO){
return new Entity(entityDTO);
}
}
These anotations are from lombok library, used for time saving :
#Getter
#Setter
#NoArgsConstructor
Then you can just make requests to Database to get entities, and place the flow of answers through the mapper to convert them to EntityDTO and send them to where ever you need. In your controller :
#Autowired
EntityMapper mapper;
In your functions, you can return :
service.getEntities().stream.map(mapper::toDTO).collect(Collectors.toList();
There is a mongo collection with lots of nested fields in it.
Since it would be too tedious to map each member in #Data classes. I had added just the members I need to use
#Data
#Document
public class MyCollection {
#Id
private String id;
String code;
String code;
}
My MongoRepository class looks like this
#Repository
public interface MyCollectionRepository extends MongoRepository {
MyCollection findById(String id);
}
Now I want to update the code field in my collection.
So I updated the code field in the entity and did
myCollection = mongoRepository.findById(1)
myCollection.setCode("newCode")
mongoRepository.save(myCollection)
Now problem is all the other fields in the database that I did not include in my entity got removed.
How can I update a selected field without affecting the others. I don't want to individually map all the members of the collection to my #Data class as it is too huge.
You need to create custom repository and in implementation of that repository, use mongoTemplate to update selected fields like this.
Query query = Query.query(Criteria.where("id").is(1));
Update update = new Update();
update.set("code", "newCode");
mongoTemplate.updateFirst(query, update, MyCollection.class);
This will use MongoDb's $set operator to set only provided fields without modifying other fields.
in official documentation I have read that jsonbackreference cannot be applied for collection
Value type of the property must be a bean: it can not be a Collection,
Map, Array or enumeration.
but is is working on my machine for collection does anybody know why?
And by the way I found in tutorial that they are using it for collection.
Well the tutorial which you have linked stated that:
We can switch around the #JsonManaged and #JsonbackReference annotations when we are trying to do the serialization.
But when we try to do the same when we try to do the deserialization then hibernate is gonna throw an exception.
Something like this:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot handle managed/back reference 'defaultReference': back reference type (java.util.List<io.adarsh.springdatajpaexp.model.PayStub>) not compatible with managed type (io.adarsh.springdatajpaexp.model.PayStub).
which means that during the deserialization we can not annotate #JsonBackReference on the List or set because, during deserialization, its value is set to an instance that has the "managed" (forward) link.
So let's say first we have set the
#Entity
public class Employee {
#OneToMany
#JsonManagedReference
List<PayStub> pasytubs;
}
and,
#Entity
public class PayStub {
#ManyToOne
#JsonBackReference
Employee employee;
}
so during deserialization hibernate will get to know that here parent is Employee and the child is PayStub which is having the #JsonBackReference, so while deserializing it will try to set the value of the employee field which is in the PayStub entity with the one which has the "managed" (forward) link (Employee entity) and it will successfully perform it.
But when we will switch the annotation
#Entity
public class Employee {
#OneToMany
#JsonBackReference
List<PayStub> pasytubs;
}
and,
#Entity
public class PayStub {
#ManyToOne
#JsonManagedReference
Employee employee;
}
Now when it goes to the #JsonBackRefernece and tries to set the value with the one which has managed reference (so it can't set a List value with a normal bean value(Paystub)).
ANSWER
I'll solve my problem regarding to this blog Jackson – Bidirectional Relationships
Thanks you.
UPDATE 2
The problem is about JsonBackReference and JsonManagedReference annotations.
With my two way relationship, I have to explicitly select one way for serialization with JsonBackReference and JsonManagedReference.
But here, I am in case to use the opposit way "Parent->Child" for a specific requierement (using the way "Child->Parent" by default)
When I inversed those two annotations, my JSON is what I'm looking for, for the special requierment.
Any idea on how to use JACKSON in a two way relationship ?
Thank you.
UPDATE 1
Here is a code simple using EntityGraph (thanks to #NeilStockton suggestion), but still don't serialize the lazy attribute in JSON :-(
Parent
#Entity
public class Parent {
#Id
#GeneratedValue
private Long id;
#column
private String parentAttribute;
#OneToOne(mappedBy = "parent", optional = false)
#JsonBackReference
private Child child;
Child
#Entity
public class Child {
#Id
#GeneratedValue
private Long id;
#column
private String childAttribute;
#OneToOne(optional = false, cascade = CascadeType.ALL)
#JsonManagedReference
private Parent parent;
Parent Repository
public interface ParentRepository extends CrudRepository<Parent> {
#EntityGraph(attributePaths = { "child" })
//a hack to use findAll with default lazy/eager mapping
Collection<Parent> findByIdNotNull();
}
Generated query :
Hibernate:
select
parent0_.id as id1_33_0_,
child1_.id as id1_32_1_,
parent0_.parent_attribute as parent_attribute2_33_0_,
child1_.child_attribute as child_attribute2_32_1_,
from
test.parent parent0_
left outer join
test.child child1_
on parent0_.id=child1_.parent_id
where
parent0_.id is not null
JSON (no child):
[ {
"id": 1
"parentAttribute": "I am the parent"
} ]
Any idea on how to force Jackson Hibernate4Module to serialize if present ?
Thank you.
I have a Spring Boot 1.3.1 back-office using JPA/hibernate for mapping entities. The front-end is an Angular2 application. The communication is a REST/JSON.
My question is about forcing EAGER loading in some queries when I have a Lazy relationship.
The solution using JOIN FETCH helped me in DAO layer (Repositories). The entity is now completely loaded in a single query as I want in controllers layer. But the serialized JSON still incomplete due to Hibernate4Module.
Bellow Hibernate4Module features can't help :-(
FORCE_LAZY_LOADING
USE_TRANSIENT_ANNOTATION
SERIALIZE_IDENTIFIER_FOR_LAZY_NOT_LOADED_OBJECTS
REQUIRE_EXPLICIT_LAZY_LOADING_MARKER
REPLACE_PERSISTENT_COLLECTIONS
Any idea is welcome. Thanks.
Finally, I solved my problem by using Custom Projection with a constructor in the select part of the query. In the new projection class, there is no "JsonIgnore" or any JPA annotation that make field not serialized by Jackson. I added more data in that projection for reach use.
Hope it'll help.
I'm having trouble figuring out exactly how to use the #RepositoryRestResource interface to create many-to-many relationships between two fairly simple entities.
For example, I have a simple parent-child entity relationship like this:
#Entity
public class ParentEntity {
#Id
#GeneratedValue
private Long id;
#ManyToMany
private List<ChildEntity> children;
}
#Entity
public class ChildEntity {
#Id
#GeneratedValue
private Long id;
#ManyToMany(mappedBy="children")
private List<ParentEntity> parents;
}
My repositories are using the vanilla Spring #RepositoryRestResource HATEOS API:
#RepositoryRestResource(collectionResourceRel = "parents", path = "parents")
public interface ParentRepository extends PagingAndSortingRepository<ParentEntity, Long> {
}
#RepositoryRestResource(collectionResourceRel = "children", path = "children")
public interface ChildRepository extends PagingAndSortingRepository<ChildEntity, Long> {
}
I’ve been successful in using POST to create the individual ParentEntity and ChildEntity but I can’t seem to figure out how to PUT/PATCH the relationships between the two using the built-in interface.
It seems like I should be able to use a PUT to send JSON to something like http://localhost:8080/api/parents/1/children, but so far I'm not finding a structure that works.
I found an answer here: How to update reference object in Spring-data rest?
By using "Content-Type: text/uri-list" instead of JSON, it is possible to "add" a resource to the collection with a PUT and pass in the URI. You can remove the resource with a DELETE.
After some digging, I discovered that the Spring documentation does describe this: http://docs.spring.io/spring-data/rest/docs/2.2.0.RELEASE/reference/html/#repository-resources.association-resource.
I always hated that text/uri-list content-type, so I did some research and it turned out there is also an undocumented JSON format which can be used:
{
"_links":{
"rel":"/555",
"rel":"/556"
}
}
The rel of the links could be anything except empty string, they could be all the same. The link part could be the whole URL form the self link of the referenced object, but the last part of the URL is enough. ( forseslash +id)