I'm trying to get info from an API in Spring, but it gives me an error because one of the fields is a Set. How to get a json with all of the info? If i use JsonIgnore, it won't give me the set i need, right?
My class:
#Data
#NoArgsConstructor
#AllArgsConstructor
#Table(name = "saloon")
public class Saloon implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#OneToMany(mappedBy = "saloon")
private Set<Service> services;
...
Collection valued attributes are by default lazily-fetched. One easy solutio is to changing it to
#OneToMany(mappedBy = "saloon", fetch = FetchType.EAGER)
But that might cause severe performance issues in various cases.
To get to an optimal solution, you need to analyze your design, ie how you are using this property in your code.
You can take a look at OpenEntityManagerInViewInterceptor.
Related
I'm trying to make a custom query but the table name is not mapped. Thi is the code, can you help me please?
#Query("FROM sbootuserss WHERE age > 17")
This is the error:
org.hibernate.hql.internal.ast.QuerySyntaxException: sbootuserss is not mapped
Do you also have a model with the appropriate annotation in your application?
#Table(name = "sbootuserss")
public class Sbootuserss implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
// another fields ...
}
And the query:
#Query("FROM Sbootuserss WHERE age > 17")
I'm trying to save a Foo object with ID=20. In my MySQL db the last row has Foo with ID=5. When I use the save function in the JpaRepository, it saves the object, but instead of using the ID I wanted it to have (20), it uses 6.
#Entity
#Data
#ToString
#NoArgsConstructor
#JsonIgnoreProperties(ignoreUnknown = true)
public class Foo implements Serializable {
#Id
private long id;
I have tried with #GeneratedValue(strategy = GenerationType.IDENTITY), but that doesn't work either. Is there a way to configure Hibernate not take the next sequential ID, but use what is stored in the object?
I am using JPA EclipseLink to model a one to many relationship between UseCase and PainPoint. I am able to insert the values fine. Thereafter, I am using JAX-RS to retrieve the data using a GET method. The GET method fails with the error - Generating incomplete JSON.
Console Log:
[EL Fine]: INSERT INTO USECASE (UseCaseID, Description) VALUES (?, ?)
bind => [1, Description]
[EL Fine]: INSERT INTO PAIN_POINT
(PainPointID, PainPointDescription, USECASE_ID) VALUES (?, ?, ?) bind
=> [2, Pain Point 1, 1]
[EL Fine]: SELECT UseCaseID, Description FROM USECASE
Nov 17, 2017 7:16:22 PM
org.eclipse.yasson.internal.Marshaller marshall SEVERE: Generating
incomplete JSON
UseCase:
#NamedQueries({#NamedQuery(name = "getAllUseCases", query = "SELECT c FROM UseCase c")})
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#NotNull
#Column(name = "UseCaseID")
private int UseCaseID;
#Column(name = "Description")
private String Description;
#OneToMany(mappedBy="usecase", cascade=CascadeType.ALL, fetch=FetchType.EAGER)
private Collection<PainPoint> painPoints = new ArrayList<PainPoint>();
PainPoint:
#NamedQueries({#NamedQuery(name = "getAllPainPoints", query = "SELECT c FROM PainPoint c")})
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#NotNull
#Column(name = "PainPointID")
private int PainPointID;
#Column(name = "PainPointDescription")
private String PainPointDescription;
#ManyToOne
#JoinColumn (name="USECASE_ID", referencedColumnName="UseCaseID")
private UseCase usecase;
DataLoader:
UseCase useCase = new UseCase("Description 1");
PainPoint painPoint1 = new PainPoint("Pain Point 1", useCase);
useCase.getPainPoints().add(painPoint1);
em.persist(useCase);
UseCaseService:
#GET
#Path("/")
public List<UseCase> getUseCases() {
List<UseCase> retVal = null;
EntityManagerFactory emf = Utility.getEntityManagerFactory();
EntityManager em = emf.createEntityManager();
retVal = em.createNamedQuery("getAllUseCases").getResultList();
return retVal;
}
Add the annotation #JsonbTransient (package: javax.json.bind.annotation.JsonbTransient) on the getter methods for cyclic references, or any other derived fields. This is equivalent to the #XmlTranisent annotation for XML generation and will prevent the conversion to JSON entering an infinite loop.
Depends on your toolset I guess, but for me using NetBeans, when the entity class is generated automatically the annotation for XML is added but not for JSON. Just match each #XmlTransient with an equivalent #JsonbTransient
According to what Dale said above. You can add the following Maven dependency
<dependency>
<groupId>javax.json.bind</groupId>
<artifactId>javax.json.bind-api</artifactId>
<version>1.0</version>
</dependency>
More information about #JsonbTransient can be found in the link
This is most probably caused by Circular Reference, There are two ways handling this issue as described on Json and Java - Circular Reference:
#JsonIgnore
#JsonManagedReference and #JsonBackReference
I suggest you take the second approach and add these two annotation two avoid circular reference issue as :
#OneToMany(mappedBy="usecase", cascade=CascadeType.ALL, fetch=FetchType.EAGER)
#JsonBackReference ///// ADD THIS ANNOTATION
private Collection<PainPoint> painPoints = new ArrayList<PainPoint>();
#ManyToOne
#JoinColumn (name="USECASE_ID", referencedColumnName="UseCaseID")
#JsonManagedReference ///// ADD THIS ANNOTATION
private UseCase usecase;
More Info:
Jackson bidirectional relationship (One-to-many) not working
Difference between #JsonIgnore and #JsonBackReference, #JsonManagedReference
http://forum.spring.io/forum/spring-projects/web/748522-one-to-many-jsonbackreference-and-jsonmanagedreference-problem
https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion
Summary:
Is there any way for Jackson to handle bidirectional references with polymorphic types where #JsonTypeInfo is also used?
A note at the bottom of this page states no but it was written in 2010 and applied to Jackson v1.6.0 so I'm hoping maybe something has changed or someone can suggest an alternative approach.
Background:
I'm getting a JsonMappingException: Infinite recursion error using the Jackson library and JPA. I know I can add #JsonIgnore as suggested here but the downside is that I loose the bidirectional association when the JPA entities are serialized/deserialized.
Jackson v1.6.0 introduced the #JsonManagedReference and #JsonBackReference annotations. This looks great but the documentation from 2010 specifically states these annotations do not work with polymorphic handling using #JsonTypeInfo, which of course is what I have.
Below is a contrived example of my entity classes:
#Entity
public class Owner implements Serializable {
#Id
#GeneratedValue
#Column(name="owner_id")
private Long id;
#OneToMany(mappedBy="pet", orphanRemoval=true, cascade=CascadeType.ALL)
private List<Pet> pets;
public List<Pet> getPets() {return pets;}
public void setPets(List<Pet> pets) {this.pets = pets;}
}
#Entity
#DiscriminatorColumn(name="pet_type")
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
#JsonSubTypes({
#Type(value = Dog.class, name = "dog"),
#Type(value = Cat.class, name = "cat"),
#Type(value = Bird.class, name = "bird") })
public class Pet implements Serializable {
#Id
#GeneratedValue
#Column(name="pet_id")
private Long id;
#ManyToOne
#JoinColumn(name="owner_id")
private Owner owner;
//#JsonIgnore
public Owner getOwner() {return owner;}
public void setOwner(Owner owner) {this.owner = owner;}
}
This is not an immediate solution, but Jackson 2.0.0 will finally have support for full Object Id handling, using #JsonIdentityInfo annotation.
Documentation is still in-progress (page should be this); but unit tests have decent examples.
The idea will be to indicate types for which Object Id is needed (or, alternatively, indicate properties), and usage is very similar to that of #JsonTypeInfo.
Jackson 2.0.0 RC1 was released a week ago, and the hope is that final 2.0.0 should go out before end of March 2012.
I think this is pretty much the simplest case for mapping a Map (that is, an associative array) of entities.
#Entity
#AccessType("field")
class Member {
#Id
protected long id;
#OneToMany(cascade = CascadeType.ALL, fetch=FetchType.LAZY)
#MapKey(name = "name")
private Map<String, Preferences> preferences
= new HashMap<String, Preferences>();
}
#Entity
#AccessType("field")
class Preferences {
#ManyToOne Member member;
#Column String name;
#Column String value;
}
This looks like it should work, and it does, in HSQL. In MySQL, there are two problems:
First, it insists that there be a table called Members_Preferences, as if this were a many-to-many relationship.
Second, it just doesn't work: since it never populates Members_Preferences, it never retrieves the Preferences.
[My theory is, since I only use HSQL in memory-mode, it automatically creates Members_Preferences and never really has to retrieve the preferences map. In any case, either Hibernate has a huge bug in it or I'm doing something wrong.]
And of course, I sweat the problem for hours, post it here, and a minute later...
Anyway, the answer is the mappedBy element of the #OneToMany annotation:
#OneToMany(cascade = CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="member")
#MapKey(name = "name")
private Map<String, Preferences> preferences
= new HashMap<String, Preferences>();
Which makes a certain sense: which field in the Many entity points back to the One entity? Even allowing that looking for a matching #ManyToOne field was too error prone, I think that what they did do (assuming the existence of a mapping table) makes even worse.