dataNucleus enhancement runtime error: dnSetid NoSuchMethodError - datanucleus

dataNucleus 5.1.1: dnSetid NoSuchMethodError
#MappedSuperclass
public class Foo {
#Transient
public Long getId() {
...
}
public void setId(Long id) {
...
}
}
#Entity
public class Bar extends Foo {
#Id
#GeneratedValue(strategy=GenerationType.TABLE, generator="gen")
#TableGenerator(name="gen", ...)
public Long getId() {
...
}
}
java.lang.NoSuchMethodError: No virtual method dnSetid(Long) in class com.example.Bar
at com.example.Bar.dnCopyKeyFieldsFromObjectId(Unknown Source:15)
at com.example.Bar.dnNewInstance(Unknown Source:10)
at org.datanucleus.enhancer.EnhancementHelper.newInstance(EnhancementHelper.java:178)
at org.datanucleus.state.StateManagerImpl.initialiseForHollow(StateManagerImpl.java:373)
at org.datanucleus.state.ObjectProviderFactoryImpl.newForHollow(ObjectProviderFactoryImpl.java:113)
at org.datanucleus.ExecutionContextImpl.findObject(ExecutionContextImpl.java:3194)
at org.datanucleus.store.rdbms.query.PersistentClassROF.findObjectWithIdAndLoadFields(PersistentClassROF.java:458)
at org.datanucleus.store.rdbms.query.PersistentClassROF.getObject(PersistentClassROF.java:364)
at org.datanucleus.store.rdbms.query.ForwardQueryResult.nextResultSetElement(ForwardQueryResult.java:180)
at org.datanucleus.store.rdbms.query.ForwardQueryResult$QueryResultIterator.next(ForwardQueryResult.java:408)
at org.datanucleus.store.rdbms.query.ForwardQueryResult.processNumberOfResults(ForwardQueryResult.java:136)
at org.datanucleus.store.rdbms.query.ForwardQueryResult.advanceToEndOfResultSet(ForwardQueryResult.java:164)
at org.datanucleus.store.rdbms.query.ForwardQueryResult.closingConnection(ForwardQueryResult.java:290)
at org.datanucleus.store.query.AbstractQueryResult.disconnect(AbstractQueryResult.java:105)
at org.datanucleus.store.rdbms.query.AbstractRDBMSQueryResult.disconnect(AbstractRDBMSQueryResult.java:251)
at org.datanucleus.store.rdbms.query.JPQLQuery$2.managedConnectionPreClose(JPQLQuery.java:654)
at org.datanucleus.store.rdbms.ConnectionFactoryImpl$ManagedConnectionImpl.close(ConnectionFactoryImpl.java:532)
at org.datanucleus.store.connection.AbstractManagedConnection.release(AbstractManagedConnection.java:83)
at org.datanucleus.store.rdbms.ConnectionFactoryImpl$ManagedConnectionImpl.release(ConnectionFactoryImpl.java:371)
at org.datanucleus.store.rdbms.query.JPQLQuery.performExecute(JPQLQuery.java:730)
at org.datanucleus.store.query.Query.executeQuery(Query.java:1966)
at org.datanucleus.store.query.Query.executeWithMap(Query.java:1873)
dnSetid should be added by enhancement. Decompiled Bar.class: there is no such method. It contains dnGetid() and other methods dn****.

The only way of overriding is to override BOTH getter AND setter.
Likely the enhancer relies on both being there, whether it is for a defined property or an overridden property.

Related

C# issue with class instantiation

I'm running a C# project on VS2019 with the following code structure:
In the Class1.cs file:
public class Class1
{
public class MyClass2 : Class2
{
...
}
private void RunAlgorithm<T>() where T : Class2, new()
{
T argInstance = new T();
...
}
static void Main(string[] args)
{
RunAlgorithm<MyClass2>();
}
}
In the Class2.cs file:
public class Class2
{
public Class2() { }
public string setParameters { get; set; }
}
I'm getting the following error for the line RunAlgorithm<MyClass2>();
'Class1.MyClass2' must be a non-abstract type with a public
parameterless constructor in order to use it as parameter 'T' in the
generic type or method 'Class1.RunAlgorithm()'
even if I change it to Public, the error persists
Well, minimally, it'll have to be protected so that MyClass can access it..
https://dotnetfiddle.net/XFeEdQ
public class Class1
{
class MyClass2 : Class2
{
}
private void RunAlgorithm<T>() where T : Class2, new()
{
T argInstance = new T();
}
public static void Main(string[] args)
{
new Class1().RunAlgorithm<MyClass2>();
}
}
public class Class2
{
protected Class2() { }
public string setParameters { get; set; }
}
So your "Class1.MyClass2
must have a public parameterless constructor" message is saying that your MyClass needs a constructor. Mine above has such a constructor even though it's not in the code; in the absence of the developer providing a constructor the compiler provides one that does nothing other than call the base parameterless constructor...
...which leads me to the next point; your MyClass2 extends Class2, and hence Class2's constructor needs to be accessible to it. While Class2's constructor is private, MyClass2's constructor can't call it. Every constructor on c# has to either call another constructor or a base constructor. If you don't specify which, the compiler will insert a call to base() for you, which will fail if the base constructor is inaccessible
For this all to work out you need a public parameterless constructor in MyClass2:
public MyClass2():base(){}
or without the base(compiler will add the base call)
or blank (compiler will add all of it)
and you need something that makes Class2's constructor accessible to MyClass2, ie declaring Class2's constructor as public or protected

InvalidDefinitionException: Cannot construct instance of `com.vehicle.datatransferobject.VehicleDTO`

In the REST endpoint I'm building in Spring Boot, I'm trying to pass my vehicleDTO to my controller. But before it reaches my controller, there is an error.
InvalidDefinitionException: Cannot construct instance of
com.vehicle.datatransferobject.VehicleDTO (no Creators, like default
construct, exist): cannot deserialize from Object value (no delegate-
or property-based Creator)
vehicleDTO
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.myvehicle.EngineType;
#JsonInclude(JsonInclude.Include.NON_NULL)
public class VehicleDTO {
#JsonIgnore
private Long id;
#NotNull(message = "vehiclenumber can not be null!")
private String vehiclenumber;
#Min(2)
#NotNull(message = "Seat count can not be less than 2!")
private Integer vehicleseatcount;
#NotNull(message = "Engine Type can not be null!")
private EngineType enginetype;
#Max(5)
private Integer vehiclerating;
private VehicleDTO(Long id, String vehiclenumber, Integer vehicleseatcount, EngineType enginetype,Integer vehiclerating){
this.vehiclenumber=vehiclenumber;
this.vehicleseatcount=vehicleseatcount;
this.enginetype=enginetype;
this.vehiclerating=vehiclerating;
this.id=id;
}
public static VehicleDTOBuilder newBuilder()
{
return new VehicleDTOBuilder();
}
#JsonProperty
public Long getId() {
return id;
}
public String getvehiclenumber() {
return vehiclenumber;
}
public Integer getvehicleseatcount() {
return vehicleseatcount;
}
public EngineType getEnginetype() {
return enginetype;
}
public Integer getvehiclerating() {
return vehiclerating;
}
public static class VehicleDTOBuilder{
private Long id;
private String vehiclenumber;
private Integer vehicleseatcount;
private EngineType enginetype;
private Integer vehiclerating;
public VehicleDTOBuilder setId(Long id) {
this.id = id;
return this;
}
public VehicleDTOBuilder setvehiclenumber(String vehiclenumber) {
this.vehiclenumber = vehiclenumber;
return this;
}
public VehicleDTOBuilder setvehicleseatcount(Integer vehicleseatcount) {
this.vehicleseatcount = vehicleseatcount;
return this;
}
public VehicleDTOBuilder setEnginetype(EngineType enginetype) {
this.enginetype = enginetype;
return this;
}
public VehicleDTOBuilder setvehiclerating(Integer vehiclerating) {
this.vehiclerating = vehiclerating;
return this;
}
public VehicleDTO createVehicleDTO()
{
return new VehicleDTO(id, vehiclenumber, vehicleseatcount, enginetype,vehiclerating);
}
}
}
My DTO has an Enum type called EngineType
public enum EngineType {
ELECTRIC, DIESEL
}
My controller looks like this
#PostMapping
#ResponseStatus(HttpStatus.CREATED)
public VehicleDTO addvehicle(#Valid #RequestBody VehicleDTO vehicleDTO)
{
VehicleDO vehicleDO = Mapper.VehicleDO(vehicleDTO);
return Mapper.makeVehicleDTO(Service.addvehicle(vehicleDO));
}
This exception :
InvalidDefinitionException: Cannot construct instance of
com.vehicle.datatransferobject.VehicleDTO (no Creators, like default
construct, exist): cannot deserialize from Object value (no delegate-
or property-based Creator)
means that Jackson didn't find a way to instantiate VehicleDTO that is the default constructor (no arg constructor) or a JsonCreator.
As you use a builder pattern you will configure the VehicleDTO class to make Jackson to instantiate VehicleDTO with the VehicleDTOBuilder such as :
#JsonDeserialize(builder = VehicleDTO.VehicleDTOBuilder.class)
public class VehicleDTO {
...
}
And annotate your builder with JsonPOJOBuilder as :
#JsonPOJOBuilder(buildMethodName = "createVehicleDTO", withPrefix = "set")
public static class VehicleDTOBuilder{
...
}
According to the javadoc, JsonPOJOBuilder is :
used to configure details of a Builder class: instances of which are
used as Builders for deserialized POJO values, instead of POJOs being
instantiated using constructors or factory methods. Note that this
annotation is NOT used to define what is the Builder class for a POJO:
rather, this is determined by JsonDeserialize.builder() property of
JsonDeserialize.
I faced this error when I used Lombok's #Builder and #Data annotations together on a POJO class that is used for connecting to an API (either for consuming or for providing response)
I removed the #Builder annotation and then it is working fine
In my case:
InvalidDefinitionException: Cannot construct instance of com.vehicle.datatransferobject.VehicleDTO (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
for the above exception, I just write Default Constructor which instantiates class and solved the problem.
Default Constructor:
public VehicleDTO() {
super();
// TODO Auto-generated constructor stub
}
If you are using Lombok - the best thing is to add these annotations to your DTO:
#AllArgsConstructor
#RequiredArgsConstructor
#Data
#Builder (optional)
In addition to davidxxx`s answer. I used Lombok. And in my case it looked like this:
#Data
#JsonDeserialize(builder = SomeClass.SomeClassBuilder.class)
#Builder(builderClassName = "SomeClassBuilder")
public class SomeClass {
// ...
#JsonPOJOBuilder(withPrefix = "")
public static class SomeClassBuilder {
}
}

Injecting Services in Entity Listener ...?

Is it by any means possible to #Inject a Service-Bean (say a session bean) into an entity Listener?
Consider the following scenario as an example
Entity:
#Entity
#EntityListeners(BookListener.class)
public class Book {
// fields, getters & setters
}
Utility class:
#Singleton
public class BookUtil {
private BookRepository bookRepo;
private List<Book> bookList;
#Inject
public BookUtil(BookRepository bookRepo){
this.bookRepo = bookRepo;
this.bookList = this.bookRepo.findAll();
}
public void refreshBooks(){
this.bookList = this.bookRepo.findAll();
}
}
Listener:
public class BookListener {
#Inject
BookUtil bookUtil // --> CAN THIS BE ACHIEVED?
#PostPersist
private void refreshCache(Book b){
bookUtil.refreshBooks();
}
}
I tried out several things I could think of but none of them successfully injected an instance of BookUtil. I could manually instantiate it, which works. But I prefer injection as then the BookRepository(inside the BookUtil) would also be injected, without me having to worry about it

How to implement database inheritance in Spring Data JPA with MapperSuperClass?

I'm trying out database inheritance of type JOINED in Spring Data JPA, referring to this article. This worked fine. But I've to implement MappedSuperClass in my project. I've implemented in the following way:
Base.java
#MappedSuperclass
public abstract class Base {
public abstract Long getId();
public abstract void setId(Long id);
public abstract String getFirstName();
public abstract void setFirstName(String firstName);
}
BaseImpl.java
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public class BaseImpl extends Base {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String firstName;
...
}
Super1.java
#MappedSuperclass
public abstract class Super1 extends BaseImpl {
public abstract String getSuperName();
public abstract void setSuperName(String guideName);
}
Super1Impl.java
#Entity
public class Super1Impl extends Super1 {
private String superName;
...
}
BaseBaseRepository.java
#NoRepositoryBean
public interface BaseBaseRepository<T extends Base> extends JpaRepository<T, Long> { }
BaseRepository.java
#NoRepositoryBean
public interface BaseRepository<T extends Base> extends BaseBaseRepository<Base> { }
BaseRepositoryImpl.java
#Transactional
public interface BaseRepositoryImpl extends BaseRepository<BaseImpl> { }
Super1Repository.java
#NoRepositoryBean
public interface Super1Repository<T extends Super1> extends BaseBaseRepository<Super1> { }
Super1RepositoryImpl.java
#Transactional
public interface Super1RepositoryImpl extends Super1Repository<Super1Impl> { }
I'm trying to save a Super1 object in a test case:
#Test
public void contextLoads() {
Super1 super1 = new Super1Impl();
super1.setSuperName("guide1");
super1.setFirstName("Mamatha");
super1.setEmail("jhhj");
super1.setLastName("kkjkjhjk");
super1.setPassword("jhjjh");
super1.setPhoneNumber("76876876");
System.out.println(super1Repository.save(super1));
}
But I'm getting the following error:
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'baseRepositoryImpl':
Invocation of init method failed; nested exception is java.lang.IllegalArgumentException:
This class [class com.example.entity.Base] does not define an IdClass
.....
Caused by: java.lang.IllegalArgumentException: This class [class com.example.entity.Base] does not define an IdClass
.......
Tried out #PrimaryKeyJoinColumn(name = "id", referencedColumnName = "id") in Super1Impl, but still getting the same error.
The error is caused by incorrect repository interface declarations.
BaseRepository<T extends Base> extends BaseBaseRepository<Base>
should be
BaseRepository<T extends Base> extends BaseBaseRepository<T>
and
Super1Repository<T extends Super1> extends BaseBaseRepository<Super1>
should be
Super1Repository<T extends Super1> extends BaseBaseRepository<T>
As currently declared, BaseBaseRepository<Base> means a repository of Base objects and Base does not have an #Id field, hence the error.

Same JPA callback method in #MappedSuperclass and child class

Can I define same JPA callback method in parent and child class as below? If yes, do I need to invoke super.onPrePersist(); in child class onPrePersist() method?
#MappedSuperclass
public abstract class AbstractEntity {
#PrePersist
protected onPrePersist() {
System.out.println("Parent onPrePersist() invoked");
}
}
#Entity
#Table(name = "child")
public class Child extends AbstractEntity {
#PrePersist
protected onPrePersist() {
**super.onPrePersist();**
System.out.println("Child onPrePersist() invoked");
}
}
I have written a unit test for the above scenario and It works. For each of the callback methods in child class, you have to invoke the parent callback method first:
#Override
#PrePersist
protected onPrePersist() {
**super.onPrePersist();**
System.out.println("Child onPrePersist() invoked");
}
You don't have to invoke the parent callback method by yourself, just don't override the #PrePersist annotated method as it hides the parent method and prevents it from being executed. If your callback methods have different names they will be invoked in the order according to their place in the hierarchy, most general classes first.
#MappedSuperclass
public abstract class AbstractEntity {
#PrePersist
protected onPrePersistParent() {
System.out.println("Parent onPrePersist() invoked");
}
}
#Entity
#Table(name = "child")
public class Child extends AbstractEntity {
#PrePersist
protected onPrePersistChild() {
System.out.println("Child onPrePersist() invoked");
}
}
This will produce the output:
Parent onPrePersist() invoked
Child onPrePersist() invoked