Problem implementing GET REST service due to JAXBException: IllegalAnnotationExceptions - java

I am having a really strange problem implementing Java REST service. I am trying receive the following model:
#Data #EqualsAndHashCode(callSuper=false, of={"primaryKey"})
#Entity #Table(name = "T_UNIQUE_IDENT_TYPE")
#Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#XmlRootElement(name="UniqueIdentifierType") #XmlAccessorType(XmlAccessType.FIELD)
public class UniqueIdentifierType extends AbstractEntityWithTime implements Serializable {
private static final long serialVersionUID = 1L;
#Id #Basic(optional = false) #Column(name = "F_TYPE_PK") #XmlTransient
#GeneratedValue(strategy=GenerationType.SEQUENCE,generator="S_UNIQUE_IDENT_TYPE") #SequenceGenerator(name="S_UNIQUE_IDENT_TYPE",sequenceName="S_UNIQUE_IDENT_TYPE")
private Long primaryKey;
#Column(name = "F_NAME", nullable=false, length=50)
private String typeName;
#Basic(optional = false) #Column(name = "F_CREATION_TIME") #Temporal(TemporalType.TIMESTAMP) #XmlTransient
private Calendar creationTime;
#Basic(optional = false) #Column(name = "F_LASTMODIFY_TIME") #Temporal(TemporalType.TIMESTAMP) #XmlTransient
private Calendar lastModifyTime;
#JoinColumn(name = "F_UNIT_PK", referencedColumnName = "F_UNIT_PK") #ManyToOne(optional = false) #XmlTransient
private SoftwareProviderUnit softwareProviderUnit;
}
My GET rest service has the following signature:
#GET
#Path("/{name}")
public UniqueIdentifierType get(#PathParam("unitId") final Long unitId, #PathParam("name") final String name) throws WebApplicationException {
Whenever I do a call on this GET service I receive 500 error containing
java.lang.AssertionError: JAXBException occurred : 2 counts of IllegalAnnotationExceptions
I was able to trace it down to the following two errors:
javassist.util.proxy.MethodHandler is an interface, and JAXB can't handle interfaces.
this problem is related to the following location:
at javassist.util.proxy.MethodHandler
at private javassist.util.proxy.MethodHandler com.rp.central.model.UniqueIdentifierType_$$_javassist_21.handler
at com.rp.central.model.UniqueIdentifierType_$$_javassist_21
javassist.util.proxy.MethodHandler does not have a no-arg default constructor.
this problem is related to the following location:
at javassist.util.proxy.MethodHandler
at private javassist.util.proxy.MethodHandler com.rp.central.model.UniqueIdentifierType_$$_javassist_21.handler
at com.rp.central.model.UniqueIdentifierType_$$_javassist_21
The weird thing is that if I change the GET method signature to return a List I get 200 with the JSON view of the object which has all the fields except for the typeName field. I am guessing that the exception is somehow related to that field. I've tried adding explicit getters such as
#XmlElement(name="typeName")
public String getTypeName() {
return typeName;
}
to try to force it to send the typeName, this gets the type name into the "List" version of the GET method but still returns 500 for the non list one. The strange thing is that I have another model which looks exactly the same as this one and works without any problems. I've been banging my head against this for a while now, any help will be greatly appreciated.
Thank you.

The exception clearly says that JAXB can't marshal your UniqueIdentifierType, because the object being marshalled is actually an instance of the class enhanced by Javassist (com.rp.central.model.UniqueIdentifierType_$$_javassist_21), and that class contains a field (added by Javassist) which can't be marshalled. Probably, ehancement is done by your ORM tool.
The most obvious solution is to return a fresh copy of the object.

Related

xHow can I have #Id string for CrudRepository in Spring with Spring Data JPA?

The problem is that I am getting an exception using #RepositoryRestResource for my UserRepository that extends JpaRepository.
The reason for that is that findById is only accepting Long or Int types by default, even I have
#Id String id; and not #Id Int id in my entity definition.
I have tried searching StackOverflow and Google, but haven't found any solutions.
The error message is as follows:
"Failed to convert from type [java.lang.String] to type [java.lang.Integer] for value '3175433272470683'; nested exception is java.lang.NumberFormatException: For input string: \"3175433272470683\""
I want to make it work with a
#Id String id;
Any suggestions?
Many thanks in advances. It's a big privilege to ask questions here.
The Entity class:
#Entity // This tells Hibernate to make a table out of this class
#Table(name = "users")
public class XmppUser {
#Id
private java.lang.String username;
private String password;
private String serverkey;
private String salt;
private int iterationcount;
private Date created_at;
// #Formula("ST_ASTEXT(coordinates)")
// #Column(columnDefinition = "geometry")
// private Point coordinates;
// private Point coordinates;
private String full_name;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "username", nullable = true)
private XmppLast xmppLast;
You must change the type of the ID type parameter in the repository to match with the id attribute type on your entity.
From the Spring docs:
Interface Repository<T,ID>
Type Parameters:
T - the domain type the repository manages
ID - the type of the id of the entity the repository manages
Based on
#Entity // This tells Hibernate to make a table out of this class
#Table(name = "users")
public class XmppUser {
#Id
private java.lang.String username;
//...
}
It should be
public interface UserRepository extends CrudRepository<XmppUser, String> {
//..
}
See:
https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/CrudRepository.html#findById(ID)
https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/Repository.html
You could try something like this:
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
#Column(name = "PR_KEY")
private String prKey;
If you want to read more about this subject you could begin looking throw here or here
according to the latest version of spring data jpa(2.1.10 GA), you can use it like
here is the link
JpaRepository is a special case of CrudRepository. Both JpaRepository and CrudRepository declare two type parameters, T and ID. You will need to supply these two class types. For example,
public interface UserRepository extends CrudRepository<XmppUser, java.lang.String> {
//..
}
or
public interface UserRepository extends JpaRepository<XmppUser, java.lang.String> {
//..
}
Notice that the second type java.lang.String must match the type of the primary key attribute. In this case, you cannot specify it as String or Integer, but it is java.lang.String instead.
Try not to name a customized class as String. It is a bad practice to use the same class name as already present in the JDK.
I think there is an approach to solve this problem.
Let's say, Site is our #Entity.
#Id
private String id;
getters setters
then you can invoke findById as follow
Optional<Site> site = getSite(id);
Note: this worked for me, I hope it will help someone.

convertToDatabaseColumn when data is not being persisted?

I have implemented method AttributeConverter.convertToEntityAttribute to load json data from the db. I am not trying to persist data, but for some reason convertToDatabaseColumn is being called.
This is what happens:
1. I call a repository method
2. then a call to AttributeConverter.convertToEntityAttribute follows -> returns a list of entity Cx. Till this point everything is normal.
3. But for some reason AttributeConverter.convertToDatabaseColumn is called right after, with that same list of entity Cx as argument -> returns stringV
4.Now convertToEntityAttribute is called again with stringV as argument, which is also strange.
Could it be that a #OneToOne relation is causing this? Why is this executing convertToDatabaseColumn if I'm not persisting an entity, at least explicitly?
All of this happens just by calling a single method in one of my repository classes:
Here is the code
public interface RSTRepository extends CrudRepository<RST, Long> {
List<RST> findByDuctNameIgnoreCase(String ductName);
}
#Entity
#Table(name="r_s_t")
public class RST {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#OneToOne
#JoinColumn(name = "r_s_id")
private Rs rs;
#Column(name = "channel")
private String channelName;
...
}
#Entity
#Table(name="r_s")
public class RS {
#Id
#Column(name = "rs_id", columnDefinition = "json")
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#Column(name = "c_x", columnDefinition = "json")
#Convert(converter = JsonToCxConverter.class)
private List<Cx> cxs;
...
}
public class Cx {
private Long someId;
private List<Long> values;
...
}
#Converter
public class JsonToCxConverterimplements AttributeConverter<List<Cx>, String>{
//this gets executed
#Override
public String convertToDatabaseColumn(List<Cx> entityAttribute) {
ObjectMapper objectMapper = new ObjectMapper();
log.info("--------------------");
return "";
}
#Override
public List<Cs> convertToEntityAttribute(String dbData) {
if (dbData == null || dbData.isEmpty()) return Collections.emptyList();
//... uses the object mapper to parse the json and return a simple object.
...
}
Like I said, this happens when calling RSTRepository.findByDuctNameIgnoreCase
Yes its really behaving like you are saying. Also when persisting RST, Converter is also called 3x.
It also called 3x when reading just RS entity, i.e. it is not caused by #OneToOne relation.
I think it is how hibernate works. It should not be a problem, you get the right data without error.
From stacktrace I see that second and third call is from AbstractRowReader.performTwoPhaseLoad().
at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.performTwoPhaseLoad(AbstractRowReader.java:241)
at org.hibernate.loader.plan.exec.process.internal.AbstractRowReader.finishUp(AbstractRowReader.java:209)
at org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl.extractResults(ResultSetProcessorImpl.java:133)
I think its something that cannot be disabled. From hibernate sources I see that entity is registered to "hydrating". I found more about it here https://stackoverflow.com/a/29538797/2044957
Another thing: This is happening only when using converter on a collection. Converter is called once if it used on single type, for example AttributeConverter<String, String>.

hibernate - could not execute statement; SQL [n/a] - saving nested object

I'm trying to save a nested object using hibernate and I receive could not execute statement; SQL [n/a] Exception
CODE
#Entity
#Table(name = "listing")
#Inheritance(strategy = InheritanceType.JOINED)
public class Listing implements Serializable {
#Id
#Column(name = "listing_id")
private String listingId;
#Column(name = "property_type")
private PropertyType propertyType;
#Column(name = "category")
private Category category;
#Column(name = "price_currency")
private String priceCurrency;
#Column(name = "price_value")
private Double priceValue;
#Column(name = "map_point")
private MapPoint mapPoint;
#Column(name = "commission_fee_info")
private CommissionFeeInfo commissionFeeInfo;
}
public class MapPoint implements Serializable {
private final float latitude;
private final float longitude;
}
public class CommissionFeeInfo implements Serializable {
private String agentFeeInfo;
private CommissionFeeType commissionFeeType;
private Double value;
private Double commissionFee;
}
public enum CommissionFeeType implements Serializable { }
Using RazorSQL I saw that hibernate defines MapPoint and CommissionFee as VARBINARY
What I can't understand, is the fact that hibernate manages to save it when commissionFeeInfo is not present. It has no problem with saving MapPoint
Does anyone have an idea about what I do wrong?
UPDATE
I found out that if all attributes of CommissionFeeInfo excepting agentFeeInfoare null, the object will be saved without problems. If one of the other attributes is != null, the errors occur.
UPDATE 2
I changed the type of all attributes of CommissionFeeInfo into String and the object will be saved without problem, but I can't let the attributes as String.
I solved the problem by adding setting
#Column(name = "commission_fee_info", columnDefinition = "LONGVARBINARY")
as annotation for the field commisionFeeInfo in the class Listing
For me,
#Column(columnDefinition="text")
solves my problem.
That solution could help for a different reason. One other reason could be Column length. Check your column length. I had the same error the reason was my data exceed the size of the column.
setSignInProvider("String length > 15 ")
Before
#Column(name = "sing_in_provider", length = 15)
and then
#Column(name = "sing_in_provider", length = 100)
I was also facing the same issue . and then I solved the problem
spring.jpa.hibernate.ddl-auto=update
For me I'm using current_date for a field in my sql table. but this is a keyword in SQL so I can't use this name. I changed the field name to current_date_and_time it works for me. also I added the column name on my entity class.
#Column(name = "current_date_and_time")

Persisting a one-to-one relation using Spring Data JPA does not work

i am working with the following tutorial Spring Data REST to access database entries via a REST Api, provided by Spring.
So right now i got the following Entity classes
Products
#Entity
#Table( name = "products" )
public class ProductsEntity implements Serializable {
#OneToOne(fetch = FetchType.EAGER)
//#JoinColumn(name="Units_id", insertable = false, updatable = false)
#JoinColumn(name="Units_id")
private UnitsEntity unitsEntity;
#Id
#GeneratedValue
#Column( name = "idproducts" )
private Long idProducts;
#Column(name = "productname" )
private String productName;
#Column (name = "Units_id")
private Long unitsid;
public ProductsEntity(){}
// Getter and setter
}
Units
#Entity
#Table(name = "units")
public class UnitsEntity implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="id")
private Long id;
#Column(name="unit")
private String unit;
#Column(name="units_id")
private Long units_id;
// Getter and Setter
}
As you can see there is a One to one relation between Products and Units
And right now i can retrieve products with the correct units but i can't persist it via the REST API. It says there is No suitable HttpMessageConverter found to read request body into object of type class ..db.entities.ProductsEntity from request with content type of application/json!
Do i need a HttpMessageConverter or is there a wrong or missing configuration element in my classes?!
** Edit: **
The JSON Requests looks like this (the unitsEntity is an existing entity):
{
"productName": "Äpfel12342344",
"unitsEntity": {
"unit" : "Anzahl",
"units_id" : 1
}
}
But now i get the following exception:
"Could not read JSON: (was java.lang.NullPointerException) (through reference chain: ...db.entities.ProductsEntity["unitsEntity"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: ...db.entities.ProductsEntity["unitsEntity"])"

Jersey ClientResponse Get List of Composite Entities

I am trying to get a Result of a List, basically a list of entities using Jersey RESTful API (Server and Client)
UserRESTClient client = new UserRESTClient();
ClientResponse response = client.getUsersByType(ClientResponse.class, String.valueOf(userType));
List<User> participants = response.getEntity(new GenericType<List<User>>() {
});
However, the above code does not work if Entity User has a Composite Object, if for instance,
public class User {
private UserId userId;
}
public class UserId {
private int id;
private int categoryId;
}
In this case, the JSON is deserialized by Jersey and returned null for the field type UserId inside Class User. I inspected the JSON returned and everything seems good at the RESTful Server end, but the nested JSON response is not clearly processed at the Client.
Any help would be greatly appreciated. I am not sure if it because of the Jackson preprocessor.
Following is the actual Code Snippet. It involves two classes Participant and ParticipantPK (primary for each Participant).
#Entity
#Table(name = "conference_participant")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "Participant.findAll", query = "SELECT p FROM Participant p"),
public class Participant implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
protected ParticipantPK participantPK;
}
#Embeddable
public class ParticipantPK implements Serializable {
#Basic(optional = false)
#NotNull
#Column(name = "conference_id")
private int conferenceId;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 150)
#Column(name = "participant_sip_uri")
private String participantSipUri;
public ParticipantPK() {
}
public ParticipantPK(int conferenceId, String participantSipUri) {
this.conferenceId = conferenceId;
this.participantSipUri = participantSipUri;
}
And the Code for retrieving ClientResponse,
List<Participant> participants = response.getEntity(new GenericType<List<Participant>>() {
});
However, the ParticipantPK (Composite PK) is null.
You only pasted a code snippet so I don't know if this part is excluded, but in my code I didn't have setters for the fields. I had getters, but no setters.
Without the setters, my composite objects themselves were non-null, but the members of those objects were themselves null.
I tried to reproduce it, but using the same data structures worked for me. What version of Jersey are you using? Is User class annotated with #XmlRootElement or are you using the POJO mapping feature?

Categories