Configuring JaVers ID for third party objects - java

I'm trying to use JaVers to store objects from a 3rd-party library that I can't change. The object definition looks something like:
interface TheirObject extends WithId{
//Other properties here...
}
interface WithId{
String getId();
}
with various implementations of that interface. The ID field is not annotated in anyway.
I tried using the default JaVers configuration and got the following error:
JaversException MANAGED_CLASS_MAPPING_ERROR: given javaClass 'interface TheirObject' is mapped to ValueObjectType, expected EntityType
So I configured JaVers as follows:
javers = JaversBuilder.javers()
.registerEntity(new EntityDefinition(TheirObject.class))
.build();
Which gives the exception:
JaversException ENTITY_WITHOUT_ID: Class 'TheirObject' mapped as Entity has no Id property. Use #Id annotation to mark unique and not-null Entity identifier
So I tried telling it about the id field:
javers = JaversBuilder.javers()
.withMappingStyle(MappingStyle.BEAN)
.registerEntity(new EntityDefinition(TheirObject.class, "id"))
.build();
Which gives the exception:
JaversException PROPERTY_NOT_FOUND: Property 'id' not found in class 'TheirObject'. If the name is correct - check annotations. Properties with #DiffIgnore or #Transient are not visible for JaVers.
I've tried a few different variations of id (e.g. Id, getId) but nothing seems to work and I haven't found the documentation very useful in working out how to proceed.
Could someone please help me configure JaVers properly so I can use it to track changes to these objects? Thanks.
Update: I've changed the interface above to better reflect the issue, as I'd over-simplified it to a point where my examples did actually work.

JaversBuilder.javers()
.registerEntity(new EntityDefinition(TheirObject.class, "id"))
.build();

Related

JAXB annotations on a Quarkus Panache entity causes REST call to fail

I have annotated a class to be a Panache Entity. However, I have also included JAXB annotations:
#Entity
#XmlRootElement(name = "Person")
#XmlAccessorType(XmlAccessType.NONE)
public class Person extends PanacheEntity {
#XmlAttribute(name = "Name")
public String name;
}
When I try to return the object from a REST call I get the following exception:
2019-12-08 08:30:01,917 ERROR [org.jbo.res.res.i18n] (vert.x-worker-thread-3) RESTEASY002005: Failed executing GET /person: org.jboss.resteasy.plugins.providers.jaxb.JAXBMarshalException: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
model.Person#name has mutually exclusive annotations #javax.xml.bind.annotation.XmlTransient and #javax.xml.bind.annotation.XmlAttribute
this problem is related to the following location:
at #javax.xml.bind.annotation.XmlTransient()
at model.Person
this problem is related to the following location:
at #javax.xml.bind.annotation.XmlAttribute(namespace="##default", name="Name", required=false)
at model.Person
at org.jboss.resteasy.plugins.providers.jaxb.AbstractJAXBProvider.getMarshaller(AbstractJAXBProvider.java:187)
at org.jboss.resteasy.plugins.providers.jaxb.AbstractJAXBProvider.writeTo(AbstractJAXBProvider.java:149)
So it seems the the Quarkus Panache framework is adding #XmlTransient to my public property.
I can get round this by changing the access of the name property to private and including getters/setters. However, this approach loses one of the benefits of Panache that your code is more compact and readible.
Is there anyway of keeping the public accessor of the class property and still making it work with JAXB?
Interesting use case.
I think we need to check that the attributes don't have any conflicting JAXB annotation before adding the #XmlTransient one automatically.
And it's probably also an issue with JSON-B/Jackson as we do the same thing.
I don't see any obvious workaround: we need to fix it in Quarkus.
Could you open a GitHub issue with a simple reproducer? Thanks!

Changing package name of hibernate managed entities

After doing some refactoring moving some classes into different packages, I started seeing following error while querying the database with criteria builder:
java.lang.IllegalArgumentException: Parameter value [in.helpi.ironlegion.db.hibernate.entity.UserEntity#1863fc] did not match expected type [in.helpi.ironlegion.cerebro.db.hibernate.entity.UserEntity
If I change the package name back to in.helpi.ironlegion.cerebro.db.hibernate.entity it works just fine.
Update
I am able to properly fetch Individual entities. But when I go for querying entities having reference to other entity I get this error. For example:
public class CommunityAccessEntity extends BaseEnity {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
#ManyToOne
#JoinColumn(name = "UserEntity_id")
private UserEntity userEntity;
...
}
If I query it on user using criteria builder like:
query.select(root).where(criteriaBuilder.equal(root.get(CommunityAccessEntity_.userEntity), user)));
I get the above error.
Has somebody also faced similar issues..
You must have implemented Serializable interface in your entity classes as it is one of the thumb rules of entity class.
Java serialization is tightly coupled with class name and package name. Your data is stored in database with your old package entity. Now you changed the package name and system will not be able to find the records in DB with your new package. This is why when you restore the package, it works.
If you are using xml based configuration for hbm, please check hbm files whether new package have been updated in all the places.

#Transient not working in hibernate

I am using hibernate 4.1.9.
My code is
#Transient
private String ldapIdTemp;
package is
import javax.persistence.Transient;
Still in hibernate query, it is not working and putting the attribute in the query.
part of query snippet (assetasset0_.ldapIdTemp as ldapIdTemp16_0_, )
I am not sure what I am doing wrong.
Can you try creating setter and getter for the field and annotate the get method with #Transient, as follows:
private String ldapIdTemp;
#Transient
public String getLdapIdTemp() {
return ldapIdTemp;
}
public void setLdapIdTemp(String ldapIdTemp) {
this.ldapIdTemp = ldapIdTemp;
}
Much depends on how you "integrated" this field in your Entity or class hierarchy. Moreover, field vs. property-access could cause an issue for your setting. See this post for a detailed explanation.
In your case, I could imagine that you either:
mixed field and property-access in your entity inheritance strategy
use XML-based configuration for Hibernate in your application.
In both cases the JPA 2.0/2.1 specification clearly states in Section 2.3.1:
It is an error if a default access type cannot be determined and an access type is not explicitly specified
by means of annotations or the XML descriptor. The behavior of applications that mix the placement of
annotations on fields and properties within an entity hierarchy without explicitly specifying the
Access annotation is undefined.
Please check that your persistent Entity classes have either field OR property-based annotations.
Check the #Transient annotation fully qualified name.
It can be from either,
org.springframework.data.annotation.Transient or javax.persistence.Transient.
Try to use javax.persistence.Transient.

Hibernate Validator - optional validation depending on lifecycle

Just started using Hibernate Validator. I have a case where a bean's id is autogenerated when saved. I'd live to validate the bean before the save. At which time the id can be null. However, when I want to update it the id must be notnull.
So the generic #NotNull on the field won't work because when I go to save it it will fail validation.
There are ways to work around this, but I was wondering if the spec or hibernate implementation have a standard way of doing this. I'd like to not have any validation errors on save and no validation on update.
Such as applying a constraint but it's ignored unless implicitly named or something like that.
Thanks in advance.
You can achieve that with groups.
public class MyBean {
#NotNull(groups = UpdateBean.class)
private Long id;
}
Validate without the id:
validator.validate(myBean);
Validate with the id:
validator.validate(myBean, UpdateBean.class);

How to write Spring Data method name to retrieve all elements in a column?

Suppose I have the class:
#Entity
public class Bean {
#Id
private String beanId;
//other fields & setters and getters
}
And the corresponding Spring Data JPA repository, where I want to have in a List<String> all the beanIds.
#RepositoryDefinition(domainClass = Bean.class, idClass = String.class)
public interface BeanRepository {
#Query("select b.beanId from Bean b")
List<String> findAllBeanId();
}
As written above, everything works as expected; but this is a simple operation and I do not want to write a query explicitly. What should the name of the method be such that Spring Data can parse it and obtain the above mentioned query (or the same functionality). I have searched in both the reference documentation as two books I have on Spring Data. The above name (findAllBeanId) and others that I have tried (findBeanId, findBeanBeanId etc.) throw the following exception as root cause:
org.springframework.data.mapping.PropertyReferenceException: No property find found for type Trade
at org.springframework.data.mapping.PropertyPath.<init>(PropertyPath.java:75)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:327)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:353)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:353)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:307)
at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:271)
at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:245)
at org.springframework.data.repository.query.parser.Part.<init>(Part.java:72)
at org.springframework.data.repository.query.parser.PartTree$OrPart.<init>(PartTree.java:180)
at org.springframework.data.repository.query.parser.PartTree$Predicate.buildTree(PartTree.java:260)
at org.springframework.data.repository.query.parser.PartTree$Predicate.<init>(PartTree.java:240)
at org.springframework.data.repository.query.parser.PartTree.<init>(PartTree.java:68)
at org.springframework.data.jpa.repository.query.PartTreeJpaQuery.<init>(PartTreeJpaQuery.java:57)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:90)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$CreateIfNotFoundQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:162)
at org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy$AbstractQueryLookupStrategy.resolveQuery(JpaQueryLookupStrategy.java:68)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.<init>(RepositoryFactorySupport.java:279)
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:147)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:153)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.getObject(RepositoryFactoryBeanSupport.java:43)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:142)
... 22 more
In the Spring docs: http://static.springsource.org/spring-data/jpa/docs/1.3.0.RELEASE/reference/html/jpa.repositories.html there is nothing about getting only particular column/property from entity by query generated from method name. So I think that currently it is not possible.
The code you showed works/should work as expected. It's simply not causing the exception you see :).
The exception is referring to a Trade, which seems to indicate that you have a repository for Trade somewhere which seems to refer to a missing property. The code you've shown is definitely not the one causing the exception. This can effectively not be the case as you're defining the query manually so that the query derivation mechanism doesn't even kick in for the repo you've shown.
I've pushed a test case for you to see this in action.

Categories

Resources