In Json: What exactly is a "direct self-reference" - java

The question may seems stupid, but for me a cycle reference is for example the object A refers an object B AND the object B refers the object A.
I am working with on a android application communicating with a GAE server with objectify DB.
My model is quite simple but I get a error:
org.codehaus.jackson.map.JsonMappingException: Direct self-reference leading to cycle (through reference chain: java.util.ArrayList[0]->com.my.model.MyMessage["senderKey"]->com.googlecode.objectify.Key["root"])
Here is my model: a MyMessage refers a MyUser (the MyUser DOESNT refer a MyMessage...
Here is the code:
public class MyMessage implements Serializable {
private static final long serialVersionUID = -1075184303389185795L;
#Id
private Long id;
#Unindexed
private String sendMessage;
#Unindexed
private String answerMessage;
private MessageStatus status = MessageStatus.FREE;
#Parent
Key<MyUser> senderKey;
Key<MyUser> answererKey;
#SuppressWarnings("unused")
private MyMessage() {
}
public MyMessage(MyUser user, String message) {
super();
this.sendMessage = message;
this.senderKey = new Key<MyUser>(MyUser.class, user.getId());
}
[... getters and setters ...]
}
.
public class MyUser implements Serializable {
private static final long serialVersionUID = 7390103290165670089L;
#Id private String id;
#SuppressWarnings("unused")
private MyUser() {
this.setId("default");
}
public MyUser(String mail) {
this.setId(mail);
}
public void setId(String mail) {
this.id = mail;
}
public String getId() {
return id;
}
}
So what is exactly a Direct self-reference ?? What is wrong with my model??
Thank you.

Key internally contains reference to parent Key, this is type-wise a reference to iteslf, i.e. a direct self-reference. This could potentially lead to endless loop, so Jackson is throwing an error.
Bottom line: Key is not serializable out-of-the-box. You might get by by writing a custom Jackson serializer/deserializer.

Related

How to fix " Failed to instantiate 'className' using constructor NO_CONSTRUCTOR with arguments" in immutable class

I use MongoDBRepository in spring boot, and when I save some object in database everything is ok. but when I find object by id spring does not allow do that.
I try to change VehicleRoutingProblemSolution type to Object type, but VehicleRoutingProblemSolution have other object field PickupService and it without default constructor to. And yes, this class has immutable... I can't create default constructors, what can I do?
import com.fasterxml.jackson.annotation.JsonProperty;
import com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
#Document(collection = "vrp_solutions")
public class VrpSolutionHolder {
// Specifies the solution id
#Id
#JsonProperty("id")
private String id;
// Specifies the solution id
#JsonProperty("solution")
private VehicleRoutingProblemSolution vehicleRoutingProblemSolution;
// Created at timestamp in millis
#JsonProperty("created_at")
private Long created_at = System.currentTimeMillis();
public VrpSolutionHolder(String id, VehicleRoutingProblemSolution vehicleRoutingProblemSolution) {
this.id = id;
this.vehicleRoutingProblemSolution = vehicleRoutingProblemSolution;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public VehicleRoutingProblemSolution getVehicleRoutingProblemSolution() {
return vehicleRoutingProblemSolution;
}
public void setVehicleRoutingProblemSolution(VehicleRoutingProblemSolution vehicleRoutingProblemSolution) {
this.vehicleRoutingProblemSolution = vehicleRoutingProblemSolution;
}
public Long getCreated_at() {
return created_at;
}
public void setCreated_at(Long created_at) {
this.created_at = created_at;
}
}
org.springframework.web.util.NestedServletException: Request
processing failed; nested exception is
org.springframework.data.mapping.model.MappingInstantiationException:
Failed to instantiate
com.graphhopper.jsprit.core.problem.solution.VehicleRoutingProblemSolution
using constructor NO_CONSTRUCTOR with arguments
I ran into the exact same problem. A persistent immutable class containing other class instances, throwing that aforementioned exception when retrieved by this repository method:
public interface ProjectCodeCacheRepository extends MongoRepository<CachedCode, String> {
public CachedCode findByCode(String code);
public List<CachedCode> findByClientId(UUID clientId);
}
...
List<CachedCode> cachedForClient = this.codeCacheRepo.`**findByClientId**`(clientId);
...
Following Erwin Smouts hints, this is nicely fixed by giving it a special constructor annotated org.springframework.data.annotation.PersistenceConstructor like so:
#Document(collection="cachedcodes")
public class CachedCode {
#PersistenceConstructor
public CachedCode(String code, UUID clientId, LocalDateTime expiration) {
this.code = code;
this.clientId = clientId;
this.expiration = expiration;
}
public CachedCode(String code, UUID clientId, long secondsExpiring) {
this.code = code;
this.clientId = clientId;
this.expiration = LocalDateTime.now().plusSeconds(secondsExpiring);
}
public UUID getClientId( ) {
return this.clientId;
}
public String getCode() {
return this.code;
}
public boolean hasExpired(LocalDateTime now) {
return (expiration.isBefore(now));
}
...
#Id
private final String code;
private final UUID clientId;
private final LocalDateTime expiration;
}
So, you should check if your VehicleRoutingProblemSolution has a) a constructor that matches the database fields (check in mongo client) and b) is annotated to be the one used by the driver (or whichever piece of Spring magic under the hood).
If your framework tool requires (visible) no-arg constructors (plus accompanying setters), and the class you have is required to stay as is, then you could roll your own, say, MutableVehicleRoutingProblemSolution where in the setters you could have :
this.vehicleRoutingProblemSolution = new VehicleRoutingProblemSolution(vehicleRoutingProblemSolution.getId(), newSolution);
Thus your MutableVehicleRoutingProblemSolution wraps around the existing VehicleRoutingProblemSolution.
Hacky smell to it, but it fits the requirements.
(Or you could try to find a tool that is able to use, not annotations on the contained fields, but annotations on constructor arguments.)
This is a problem where the corresponding class does not have a no-arg constructor like - I was facing an issue with java.io.File.
Solution:
In general - change the declaration to Object class and convert where we are using the class.
from
class MyClass{
File myfile;
}
to
class MyClass{
Object myFile;
}
For anyone using lombok, you need to remove the #Builder annotation on your class and use #Data instead, or follow the above solution to provide a specialized constructor
Oddly, I received this when I attempted to decorate a custom interface with ...
#Document(collection = "Person")
Example:
package test.barry.interfaces;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.UpdateDefinition;
#Document(collection = "Person")
public interface CustomRepository
{
void updatex(Query filterPredicate, UpdateDefinition updatePredicate);
}

Fasterxml jackson polymorphism error

I'm using wildfly with resteasy + jackson and I've created a super abstract class named Participation, a subclass InnovationParticipation and a simple rest service. Here is the code:
//Super abstract class
#JsonTypeInfo(use=Id.NAME, property="theType", include = JsonTypeInfo.As.PROPERTY)
#JsonSubTypes({
#JsonSubTypes.Type(value=InnovationParticipation.class, name="innovation"),
})
public abstract class Participation implements Serializable {
private static final long serialVersionUID = -8008289902553477716L;
private String type;
private String groupName;
private String groupEmail;
//Constructor, getters and setters
}
//subclass
public class InnovationParticipation extends Participation {
private static final long serialVersionUID = -2843212924880669778L;
private String area;
private String innovationType;
private String title;
private String ideaDescription;
//Constructor, getters and setters
}
//rest request
public class ParticipationRequest implements Serializable {
private static final long serialVersionUID = -8919114519349685945L;
private Participation participation;
}
//rest method
#POST
#Path("/participate")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public ParticipationResponse participate(ParticipationRequest request) {
System.out.println("Yuppiiiii");
}
But Wildfly returns this error:
com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of beans.Participation, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
at [Source: io.undertow.servlet.spec.ServletInputStreamImpl#dd39841; line: 1, column: 18] (through reference chain: webservices.requests.ParticipationRequest["participation"])
Can anyone try to solve my problem?
Thanks in advance

Jackson: remove some values from json and keep some null values

I have a model like this:
public class Employee {
#JsonProperty("emplyee_id")
private Integer id;
#JsonProperty("emplyee_first_name")
private String firstName;
#JsonProperty("emplyee_last_name")
private String lastName;
#JsonProperty("emplyee_address")
private String address;
#JsonProperty("emplyee_age")
private Byte age;
#JsonProperty("emplyee_level")
private Byte level;
//getters and setters
}
now I need to create two JSONs using this (only) model.
the first one must like this for example:
{
"employee_id":101,
"employee_first_name":"Alex",
"employee_last_name":"Light",
"employee_age":null,
"employee_address":null
}
and the second one must like this for example:
{
"employee_id":101,
"employee_level":5
}
by the way, I already tested #JsonIgnore and #JsonInclude(JsonInclude.Include.NON_NULL).
the problem of the first one (as much as I know) is, those fields can't be included in other JSONs (for example if level get this annotation, it won't be included in the second JSON)
and the problem of the second one is, null values can't be included in JSON.
so can I keep null values and prevent some other property to be included in JSON without creating extra models? if the answer is yes, so how can I do it? if it's not I really appreciate if anyone gives me the best solution for this state.
thanks very much.
it could be useful for you using #JsonView annotation
public class Views {
public static class Public {
}
public static class Base {
}
}
public class Employee {
#JsonProperty("emplyee_id")
#JsonView({View.Public.class,View.Base.class})
private Integer id;
#JsonProperty("emplyee_first_name")
#JsonView(View.Public.class)
private String firstName;
#JsonProperty("emplyee_last_name")
#JsonView(View.Public.class)
private String lastName;
#JsonProperty("emplyee_address")
private String address;
#JsonProperty("emplyee_age")
private Byte age;
#JsonProperty("emplyee_level")
#JsonView(View.Base.class)
private Byte level;
//getters and setters
}
in your json response add #JsonView(Public/Base.class) it will return based on jsonview annotations
//requestmapping
#JsonView(View.Public.class)
public ResponseEntity<Employee> getEmployeeWithPublicView(){
//do something
}
response:
{
"employee_id":101,
"employee_first_name":"Alex",
"employee_last_name":"Light",
"employee_age":null,
"employee_address":null
}
for the second one
//requestmapping
#JsonView(View.Base.class)
public ResponseEntity<Employee> getEmployeeWithBaseView(){
//do something
}
response
{
"employee_id":101,
"employee_level":5
}

NullPointer while creating a class with attribute of another class

I work on a project that stores my Items , Persons and action when I Borrow some Item to some Person
This project is based on a YouTube tutorial for classical library of books.
I'm sorry for I will post some more code because I want to give some idea how I'm doing it. I personally think that there is a problem with how I get the instances of ItemClass or PersonClass. Or something with inheritance around BorrowClass.
Now first two Methods in BorrowClass works okay, creating items and persons and adding to the lists, but when I try to create new BorrowClass containing and instance of items or persons it throws nullPointer, yet through debug I was able to see borrowed in variables and everything seemed to be not null or does the red squares means problem ?
I create ItemClass
public class ItemClass implements Serializable {
private static final long serialVersionUID = 1L;
private int isbn;
private String title, author;
private String otherInfo;
public ItemClass(String title,String otherInfo, String author,int isbn) {
this.isbn = isbn;
this.title = title;
this.author = author;
this.otherInfo = otherInfo;
}
Then PersonClass
public class PersonClass implements Serializable {
private static final long serialVersionUID = 1L;
private int telephone;
private String name, surename, email;
public PersonClass(String name,String surename, int telephone,String email) {
this.name = name;
this.surename = surename;
this.telephone = telephone;
this.email = email;
}
Then BorrowCLass
public class BorrowClass implements Serializable {
private static final long serialVersionUID = 1L;
private ItemClass item;
private PersonClass person;
private Date borrowDate;
private Date expireDate;
public BorrowClass(ItemClass item, PersonClass person, Date borrowDate,
Date expireDate) {
this.item = item;
this.person = person;
this.borrowDate = borrowDate;
this.expireDate = expireDate;
}
Now All above I handle in Library class
public class Library extends Object implements Serializable {
private static final long serialVersionUID = 1L;
private List<ItemClass> listOfItems;
private List<PersonClass> listOfPersons;
private List<BorrowClass> listOfBorrowed;
public Library() {
listOfItems = new ArrayList<ItemClass>();
listOfPersons = new ArrayList<PersonClass>();
listOfBorrowed = new ArrayList<BorrowClass>();
}
public void addItemtoItemsCollection(ItemClass item) {
listOfItems.add(item);
}
public void addPersontoPersonCollection(PersonClass person) {
listOfPersons.add(person);
}
public void addBorrow(BorrowClass borrowed) {
listOfBorrowed.add(borrowed);
}
Also would be nice if someone could explain the meaning of
private static final long serialVersionUID = 1L;
because in the video I didn't get it and I would like to know.
Thanks for any answer.
About serialVersionUID :
So... basically at some point you may want to serialize your objects and save them somewhere ( like in a file or in db), so that you can deserialize them later. Now, serialVersionUID field is used to know, if you are using the same class definition as that was being used when this object was created an serialized.
So... whenever you make a change to some class that is serializable, you increase the serialVersionUID by 1 so that any seiralized object of old class version is not wrongly deserialized using the current class version.
Ladies and gentleman I humbly apologise for my stupidity. I have function load from file and I was loading an OLD library file where list borrow was still not existing there fore no list to add to. And here I have the nullPointer. I was stuck on this for a while but only for my stupidity :) Thanks all for help. You can close the topic

How to support backwards-compatible serialization when refactoring a class into an interface in Java?

Unfortunately, the situation in the question title has already happened several years in the past.
I have an Id interface which extends Serializable and contains getters for a name and id number. There is a matching IdImpl class which implements the interface. However, at some point in the past, Id was the class. There is also a serializable container object which has member fields of type Id. These container objects have been being serialized to a database for several years, so there are versions of the container object out there containing both types of Ids. When attempting to deserialize the old objects, we get an InvalidClassException. How can I deserialize the old container objects which contain the old Id concrete class instances?
Full disclosure: a couple of other changes to the Id interface have been made over the years, but I thought they looked like compatible changes (added a field to IdImpl and a getter to Id for "String idType"; generified Comparable). Could one of these changes be causing the problem too?
The classes look something like this:
// current Id interface
public interface Id extends Serializable, Comparable<Id> {
String getName();
int getIdNumber();
}
// current Id implementation
public class IdImpl implements Id {
private static final long serialVersionUID = 10329865109284L;
private String name;
private int idNumber;
IdImpl(String name, int idNumber) { this.name = name; this.idNumber = idNumber; }
#Override public String getName() { return name; }
#Override public int getIdNumber() { return idNumber; }
#Override public int compareTo(Id id) { /* some code here */ }
}
// the container object
public ContainerForm implements Serializable {
private static final long serialVersionUID = -3294779665912049275L;
private String someField;
private Id user;
private String someOtherField;
// getters and setters
}
// this is what the _old_ Id concrete class looked like
// (from source control history; not in current project)
public class Id implements Serializable, Comparable {
// never had a serialVersionUID
private String name;
private int idNumber;
Id(String name, int idNumber) { this.name = name; this.idNumber = idNumber; }
public String getName() { return name; }
public int getIdNumber() { return idNumber; }
public int compareTo(Object id) { /* some code here */ }
}
The exception we get when trying to deserialize container objects is:
java.io.InvalidClassException: mypkg.people.Id; local class incompatible: stream classdesc serialVersionUID = -6494896316839337071, local class serialVersionUID = -869017349143998644
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:562)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1583)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1496)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1732)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1947)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1871)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1753)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
at mypkg.forms.FormFactory.getForm(FormFactory.java:3115)
... 34 more
As a general rule, not using serialVersionUID and turning a class into an interface is a very difficult transition to support.
In this specific instance, i believe you could support the old Id implementation by:
create a class (call it OldId) which has the old serialVersionUID and old implementation of Id (it should implement Id).
create a custom subclass of ObjectInputStream and override the readClassDescriptor() method. call the parent readClassDescriptor and
if the returned ObjectStreamClass has the Id class name and the old serialVersionUID, return the ObjectStreamClass for the new OldId class
otherwise return the given descriptor

Categories