How to delete unnecessary Ids of #JsonIdentityInfo? - java

I have a problem with #JsonIdentityInfo. I'm getting two id in json file.
{
"name" : "Tim",
"#id" : 1, // fasterxml garbage
"id" : 3,
"company" : {
"name" : "Microsoft",
"employees" : [1], // garbage too
"#id" : 2, // fasterxml garbage
"id" : 3
}
}
Here is my entity:
#Entity
#Table(name = "company")
#JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, property = "id")
public class Company implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column
private String name;
#OneToMany(mappedBy = "company")
#Cascade(value = CascadeType.ALL)
private Collection<Employee> employees;
How to delete unnecessary Ids?
UPD:
I'm using com.fasterxml.jackson

This is an old question and you probably got the answer by now, but from reading it, it would seem your problem with additional ids comes from the generator you use.
IntSequenceGenerator will have Jackson generates auto-incremented ids, and you specified that you want them as id property (and as you already have an id property, I guess that's why Jackson produces #id). What you want is Jackson to use your existing id property, and for that you simply need to use the PropertyGenerator.
You will also need to use the scope attribute on the annotation as well as use it also on the Employee class, as you have two independent id sequences.
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id", scope=Company.class)
public class Company {}
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id", scope=Employee.class)
public class Employee {}
This should produce for your example
{
"name" : "Tim",
"id" : 3,
"company" : {
"name" : "Microsoft",
"employees" : [3],
"id" : 3
}
}

You can use JSON annotation like this to ignore them:
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
#JsonIgnoreProperties({"id", "name"})
When creating JSON object, "id" and "name" will not be in the JSON object.

Related

JSON returns one field with ID and other field with full object, when both objects are same

I have a class like below.
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#EqualsAndHashCode
#Entity
#Table( name = "hires", indexes = { #Index( name = "idx_hire_date", columnList = "date DESC" ) }, uniqueConstraints = {
#UniqueConstraint( columnNames = { "vehicle_id", "po_number" } ) } )
#DynamicUpdate
#JsonIdentityInfo( generator = ObjectIdGenerators.PropertyGenerator.class, property = "id" )
public class Hire implements Serializable {
#Id
#GeneratedValue( strategy = GenerationType.IDENTITY )
int id;
#OneToOne( targetEntity = Driver.class, fetch = FetchType.EAGER )
#JoinColumn( name = "pass_payer", referencedColumnName = "id", nullable = true )
Driver passPayer;
#OneToOne( targetEntity = Driver.class, fetch = FetchType.EAGER )
#JoinColumn( name = "driver_id", referencedColumnName = "id", nullable = true )
Driver driver;
...
}
I get this object via a Rest endpoint.
The problem is when the field passPayer and driver objects are equal, in the returning JSON, the driver field contains only the ID (which is just an integer value) and passPayer field has all the object fields.
"passCost": 300.0,
"passPayer": {
"id": 9,
"firstName": "XXXX",
"lastName": "XXXXXX",
"idNo": "000000000000"
},
"driver": 9,
"driverSalary": xxxx.xx,
When these fields have different objects, both fields show full details like below.
"passCost": 300.0,
"passPayer": {
"id": 9,
"firstName": "XXXX",
"lastName": "XXXXXX",
"idNo": "000000000000"
},
"driver": {
"id": 4,
"firstName": "YYYYYY",
"lastName": "YYYYYYY",
"idNo": "10101010101"
},
"driverSalary": 00000.00,
I need both objects to contain data (fields. [id, firstName, lastName, idNo]) whether they are equal or not.
Any clue is appreciated!
This is caused by #JsonIdentityInfo( generator = ObjectIdGenerators.PropertyGenerator.class, property = "id" ), check the docs. To cite :
Annotation used for indicating that values of annotated type or
property should be serializing so that instances either contain
additional object identifier (in addition actual object properties),
or as a reference that consists of an object id that refers to a full
serialization.
Since both fields are referencing the same object, the second one is serialized as a reference to the first object.
In my experience, this annotation is mostly used to deal with circular references, so you can:
remove it, if your use case allows it(no circular references in object)
or you can use DTOs(which is the prefered approach anyway)

Spring MappingException: Could not determine type

I am building a Single-Page-Webapp for testing-scenario and i am using spring-jpa. I want to use this JSON data-model for my post-request:
{
"id": 1,
"title": "test-title",
"releaseDate": "2021/12/15",
"rating" : {
"stars" : 5,
"comment" : "very exciting"
}
}
If i start my application, i get the following error:
Caused by: org.hibernate.MappingException: Could not determine type for: de.demo.dto.Rating, at table: books, for columns: [org.hibernate.mapping.Column(rating)]
If i am declaring the class "rating" with #Entity and add the field "id", the application is starting without errors (if i am using an #OneToOne annotation). But for the class "Rating" i do not want to use an own data table with an "id". Can everyone help me with my issues? How do i fix this problem?
Class books:
#Getter
#Setter
#Entity
public class Books {
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
#Column(unique = true, nullable = false)
private int id;
private String title;
private String releaseDate;
private Rating rating;
}
class Rating
#Getter
#Setter
public class Rating {
int stars;
String comment;
}
Thanks!
So seems you want one to one relationship but dont want it to be in another table, best thing comes to my mind is saving that rating as a json object String. So you might need to do cruds with some third party library like GSON:
Gson gson = new Gson(); // Or use new GsonBuilder().create();
MyType target2 = gson.fromJson(json, MyType.class); // deserializes json into target2

How do I make a fully populated reference object in MongoDB using java spring annotations

I am getting a primary unique constraint error when I add the same object to a table in an array in my MongoDB table. I really want the whole object in the array and not just a reference to it.
Ok so I have this case where I have a book table with lots of books each with an id as the primary key that is unique.
Book table:
{
"_id" : "1234-sc-myKey",
"title" : "Tom Sawyer",
"author" : "Mark Twain"
}
Then I have a store table:
{
"_id" : "myStoreId-1",
"name" : "book store 1",
"books" : [
{
"_id" : "1234-sc-myKey",
"title" : "Tom Sawyer",
"author" : "Mark Twain"
},
{
"_id" : "5678-pc-myKey",
"title" : "Huck Finn",
"author" : "Mark Twain"
}
]
}
I get a primary key constraint error when I add the same book to another store. I know that I can do this annotation #DBRef and get the store table to look like this:
{
"_id" : "myStoreId-1",
"name" : "book store 1",
"books" : [
{
"$ref" : "Book",
"$id" : "1234-sc-myKey"
}
}
But then I would have to query the database again for each book to get a list of titles. Is there a way to have the books in the store table but also have a unique primary key on the books? I am sure there is a cool java spring annotation for this but I am not finding it.
Java info:
class Book
#JsonAutoDetect
#JsonIgnoreProperties(ignoreUnknown = true)
#Document(collection = "Book")
#CompoundIndexes({
#CompoundIndex(name = "pk_idx", def = "{'bookId':1, 'type': 1, 'myKey': 1}", unique=true)
})
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class Book {
#Id
private String id;
etc...
}
class Store:
#JsonAutoDetect
#JsonIgnoreProperties(ignoreUnknown = true)
#Document(collection = "Store")
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class Store {
#Id
private String id;
private String name;
//this is the solution where it throws unique constraint
private List<Book> books;
//this is the solution I don't like
#DBRef
private List<Book> books;
}
Try adding #Reference above private List<Book> books; in class Store

Spring Jackson deserialization only picks the first item of an array

I building an api rest with spring boot. I have a parent-child relationship in witch the child its an array of objects.
The problem is that deserialization only picks the first item of the array. Everything else seems to work fine. The parent and the child are pesisted in the database too.
I send something like this:
"user": {
"name": "foo",
"childs": [
{
"name": "bar",
....
},
{
"name": "foobar",
....
}
],
....
}
But got persisted this:
"user": {
"id": 1,
"name": "foo",
"childs": [
{
"id": 1,
"name": "bar",
....
}
],
....
}
Any clue on this?
Update
Parent Entity:
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id",
scope = User.class)
#Entity( name = "users" )
#Table( name = "users" )
public class User extends ModelEntity {
Model's fields...
...
#JsonView( value = {DTOViews.PrivateProfile.class, DTOViews.Owner.class} )
#JsonManagedReference( value = "User-ProfessionalExperience" )
#OneToMany( mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY )
private Set<ProfessionalExperience> professionalExperiences;
}
Child entity:
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id",
scope = ProfessionalExperience.class)
#Entity
#Table( name = "professional_experiences")
public class ProfessionalExperience extends ModelEntity {
Model's fields...
...
#JsonBackReference( value = "User-ProfessionalExperience" )
#ManyToOne
#JoinColumn(name = "user_id", nullable = false)
private User user;
}
Controller:
#RequestMapping(method = RequestMethod.POST)
public MappingJacksonValue create(#RequestBody #Valid User userToCreate, BindingResult result) {
...
}
Thank you all in advance.
So, I finally solved it. The issue comes from the relationship collection type and hasCode() / equals() methods.
All the entities in my model extend from "ModelEntity" class. This class provides id and record active fields for all extending models and a hasCode/equals method based on these fields. As the relationship between "User" and "ProfessionalExperience" is defined as a set, it can't store duplicated elements.
So, to tell jackson that the children are different elements, we need to override hasCode/equals in each model class with the fields defined in each one.

Spring Data JPA and Jackson JsonIdentity weirdness with one-to-many relationships

I'm observing some weird jackson behavior which I need help with. I have the following two one-to-many relationships in my simple library application:
Book contains a list of BookCopy
Library contains a list of BookCopy
The idea is that a single book may have many copies, and each library owns copies of books (and not books directly). That said, here's the relevant snippet of my code:
Book class:
#Entity
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Book {
//.. rest omitted
#OneToMany(mappedBy = "book")
private List<BookCopy> bookCopies;
}
Library class:
#Entity
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Library {
#OneToMany(mappedBy = "library")
private List<BookCopy> bookCopies;
}
BookCopy class:
#Entity
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class BookCopy {
#ManyToOne
#JoinColumn(name = "book_id")
private Book book;
#ManyToOne
#JoinColumn(name = "library_id")
private Library library;
}
Now, when I add a book and a library, without the copies, things work fine. When I add a book-copy object though, I get some seriously strange output from the serialized version of bookRepository.findAll().
This is a sample json I'm POST-ing to add a book copy:
{
"book": {
"id": 1
},
"library": {
"id": 4
}
}
.. and things are persisted perfectly into the DB (postgres). However, when I retrieve all books, here's a sample weird JSON I get (snipped for brevity):
[
{
"id": 1,
"title": "Effective Java",
"bookCopies": [
{
"id": 5,
"book": 1,
"library": {
"id": 3 // ...
}
}
},
2
]
Note the last part - the weird 2 sticks out of nowhere - in a list of book objects. Am I doing something seriously wrong - or is this some jackson bug I'm hitting?

Categories