JsonBackReference is working for collection - java

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)).

Related

ManyToOne relationship is always null when finding entity in the same transaction

I have a ConversationEntity with a ManyToOne relationship with ModeratorEntity
#Entity
#Table(name="CONVERSATIONS")
public class ConversationEntity {
#Id
private Integer id;
private Integer moderatorId;
#ManyToOne
#JoinColumn(name="moderatorId", insertable=false, updatable=false)
private ModeratorEntity moderator;
}
#Entity
#Table(name="MODERATORS")
public class ModeratorEntity {
#Id
private Integer id;
private Integer name;
}
And a service class with a transactional method that first of all saves the ModeratorEntity and after that the ConversationEntity with the moderatorId previously created
#Transactional
public void doStuff(Moderator moderator, Integer conversationId) {
Integer moderatorId = moderatorService.save(moderator);
Integer conversationId = conversationService.save(conversationId, moderatorId);
//do other stuff
Conversation conversation = conversationService.findById(conversationId);
}
When I'm trying to find the ConversationEntity by the id in the same transaction, a few lines below, I'm getting the ConversationEntity with the field moderatorId set but with the ModeratorEntity object = null.
If I do this outside the transaction I'm getting the ModeratorEntity object properly set.
I tried using saveAndFlush in ModeratorRepository and ConversationRepository and set FetchType.EAGER in the ManyToOne relationship but none of them worked
There are many questions about similar problems. For example #Transactional in bidirectional relation with Spring Data returns null and Hibernate: comparing current & previous record.
As long as you are within a single transaction you'll always get the same instance and no data is actually loaded from the database. And since (it seems at least) you never set the reference to the ModeratorEntity it stays null.
Once you are in a new transaction the database gets accessed and JPA populates a new instance, now including a ModeratorEntity reference.
The possible fixes therefore are:
Instead of an id let moderatorService.save return an entity and set that in the Conversation. You might as well drop the moderatorId. This is the idiomatic way to do things with JPA.
Perform the query in a separate transaction. Springs TransactionTemplate might come in handy. While this does work it causes JPA internals to bleed into your application which I recommend to avoid.

Marshall a hibernate pojo class with OnetoMany relation

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.

Classes Relationships with JPA

I have a set of Java classes with the following UML diagram:
public class Invoice {
#Id
private long id;
...
}
public class InvoiceDetail {
#Id
private long id;
...
private String productName;
private int quantity;
private double price;
}
My purpose is using JPA annotations to establish the different relationships between them. There is a composition relationship between Invoice and InvoiceDetail, which is resolved using #Embedded and #Embeddable annotations for Invoice and InvoiceDetail respectively. However, a problem appears by establishing the relationships between InvoiceDetail, Class3 and Class4. In these relationships InvoiceDetail must be annotated as #Entity. However, when a class is annotated at the same time as #Entity and #Embeddable, the corresponding server will throw a runtime error during the deployment.
Basing on the information of this website, I have written the following possible solution:
#Entity
public class Invoice {
#Id
private long id;
...
#ElementCollection
#CollectionTable(name="INVOICEDETAIL", joinColumns=#JoinColumn(name="INVOICE_ID"))
private List<InvoiceDetail> invoiceDetails;
...
}
Would be this right in order to resolve my problem?
Thanks in advance.
Although without knowing what the classes really are it is hard to tell, I suppose that you have a design problem. The composition between Class1 and Class2 says that any Class2 instance only exists within the lifecycle of a corresponding Class1 instance. But on the other hand you have Class3 instances and Class4 instances which can / must have a relationship to a Class2 instance.
What I'm trying to say is that from my point of view the relationship between Class1 and Class2 should be a simple association and not a composition. Following this path Class2 would be an Entity in JPA and then you should have your problem solved.
I usually use #Embeddable for classes whose instances never exist by themselfes and #Entity for any class whose instances can exist without other instances. An address for example could be implemented either way but not on the same system. Address would be #Embeddable if I don't want to link addresses but it had to be #Entity if I want to make sure the same address isn't saved in more than one row.
[edit: added after classes 1 and 2 were renamed to Invoice and InvoiceDetails]
Having a composition between Invoice and InvoiceDetails makes perfect sense. But I still think you should avoid the need of double personality for InvoiceDetails. I can think of two solutions (both refactorings):
If you prefer having InvoiceDetails as #Embeddable you could change the associations of Class3 and Class4 to Invoice instead of InvoiceDetails. InvoiceDetails would still be traversable via the Invoice object.
If you prefer keeping the associations as is you could declare InvoiceDetails to be an entity. You could still achieve your composition with a cascading delete (see javax.persistence.CascadeType). As it seems that InvoiceDetails already has it's own table, this probably is the better option.
I checked my JPA applications and haven't found any occurence of the same class being #Entity and #Embeddable. Honestly, I doubt if this is possible at all because the official javadoc of #Embeddable says:
Specifies a class whose instances are stored as an intrinsic part of an owning entity and share the identity of the entity.
As #Entity has it's own identity, you would try to declare the same object having two identities - and this can't work.
[/edit]
[edit2: adding code for solution proposal #2]
This code should work with some assumptions (see below). This is the implementation of bi-directional navigation for a 1:n-relationship.
#Entity
public class Invoice {
#Id
private long id;
#OneToMany(mappedBy="invoice", cascade = CascadeType.ALL)
private List<InvoiceDetail> details;
}
#Entity
public class InvoiceDetails {
#Id
private long id;
#ManyToOne
#JoinColumn(name="invoice_id")
private Invoice invoice;
}
Assumptions: Tables are named like the entities, the foreign key column for invoice_details table is named "invoice_id" and both tables have a primary key column named "id". Note that the mappedBy-value "invoice" refers to the entity field while the name-value "invoice_id" refers to the database table.
Be cautious when deleting an Invoice object whose InvoiceDetails still are referenced by your Class3 or Class4 instances - you have to release these references first.
For information about JPA refer to these resources:
The Java EE 7 Tutorial: Persistence
Wikibooks: Java Persistence
Javadoc of Package javax.persistence
[/edit]

Spring Data JPA get entity foreign key without causing the dependent entity lazy load

I have an #Entity A that references another entity B using OneToOne relation ship. I fetch entity A using spring data JpaRepository
A a = aRepository.findById(1);
int b_id = a.getB().getId();
As you can see I need to query ID of the B table, however in order to do that, I need to call getter of the B table, which will cause lazy-loading the B table itself. I do not want to do that because the only thing I need is the get ID, nothing else, and that ID is present in the first A table.
Is there any trick that will help me to get ID of the dependent table without triggering new query?
UPDATE
#Entity
class A {
#Id
private Long id;
#OneToOne
private B b;
}
#Entity
class {
#Id
private Long id;
}
Without looking at the entity mapping, I suspect, your entity classes might be using hibernate annotations on the field. With this if you call even the getId() method as in a.getB().getId() on the entity it will result in initializing the proxy (i.e., B object) and hits the database to fetch it.
So if the intent is only to get the id of the entity you can place the hibernate annotations on the getter methods instead. This doesn't result initializing the proxy (B object) to return the id. Although accessing any property other than id will result in hitting the database.
Have a look at related bug at HHH-3718
So, try using property/getter AccessType instead of field access. As an example instead of placing the annotations on field
#Id
#GeneratedValue(...)
private long id;
place them on the getters
#Id
#GeneratedValue(...)
public long getId() { ... }
Make sure you make similar changes to all the fields of B entity. Although you can explore #Access(AccessType.PROPERTY/FIELD) later.
There is already a related bug HHH-3718 regarding this behavior.
And a related topic on hibernate forum regarding field vs property access type that might be of interest for you Field Vs Property access
Posting your entities classes would help, if this doesn't resolve the issue.

javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist?

I have Employee Class like below
#Entity
public class Employee{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
id;
Department dept;
Address add;
#JoinColumn(name = "manager_emp_id", insertable = false, updatable = false)
Manager Employee;
//other fields and their getters and setters
}
when i call entityManager.persist(Employee emp) to persist i get below error
javax.persistence.PersistenceException:
org.hibernate.PersistentObjectException: detached entity passed to
persist : com.myComp.Employee
i verfied employee.id is null or 0. So i am not getting why its considering Employee as detached instance instead of transient ?
Can it because its some member variable(instead of Employee) has id as non zero value and hibernate is trying to persist ? If yes
can i get which exact class is detached instance as there are many member variables?
Guessing but:
manager is probably also Employee, when you set on your new Employ objcet the manager, most likely you are using existing one but that you did not retrieve it from the same EnityManger (or haven't marge it). And the exception. Without the your DAO code or other entities it is only guessing.
So i am not getting why its considering Employee as detached instance instead of transient ?
I cannot tell you either, because your code example is too brief (and also snytactically incorrect).
Can it because its some member variable(instead of Employee) has id as non zero value and hibernate is trying to persist ?
Possibly.
If yes can i get which exact class is detached instance as there are many member variables?
This you already have. Based on the exception you posted, it is an instance of Employee. Based on the given info I have to guess, that you have employee also reference itself (maybe via department?). If you are not cascading the persist operation you might hit this exception when one of the lower level employees is tried to be persisted. But as said, your sample is too brief and incomplete as to really give you a full fledged answer.

Categories