Error updating Spring-data-jpa on MappedSuperclass - java

I got an error on startup upgrading from version 1.4.3 to 1.5+ or 1.6.0;
I am using Hibernate 4.3.5
The exception is:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'IAccountRepository': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: This class [class com.model.entities.BaseEntity] does not define an IdClass
and the entities:
#MappedSuperclass
#EntityListeners(EntityAuditListener.class)
public abstract class BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Audited
#Basic(optional = false)
#Column(name = "isactive", nullable = false, columnDefinition = "BOOLEAN DEFAULT TRUE")
private boolean isActive = true;
protected BaseEntity() {
}
protected BaseEntity(boolean isActive) {
this.isActive = isActive;
}
........... more attributes and getters and setters
}
#Entity
#Table(name = "accounts", schema = "public")
#SequenceGenerator(name = "seq_account", sequenceName = "seq_account", initialValue = 1, allocationSize = 1)
#Audited
public class Account extends BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_account")
#Column(name = "accountid")
private Long accountId;
---- more attributes and getters and setters
}
To me it looks like Spring-data-jpa checks hierarchy in the same way Hibernate does but considering the super class as an entity.
Do you know if it's my error or a bug and any workaround?
Many thanks.
EDIT
MY repositories are as follow:
#Transactional(propagation = Propagation.MANDATORY)
#NoRepositoryBean
public interface IBaseRepository<T extends BaseEntity, ID extends Serializable> extends JpaRepository<T, ID>, JpaSpecificationExecutor<T> {
public Page<T> findByIsActiveTrue(Pageable pageable);
public List<T> findByIsActiveTrue();
}
#Transactional(propagation = Propagation.MANDATORY)
public interface IAccountRepository extends IBaseRepository<Account, Long> {
-- mix of queries by method name like:
public Account findByAccountIdAndIsActiveTrue(Long accountId);
-- and #Query like:
#Query(value = "SELECT COALESCE(SUM(a.accountCreditLimit), 0) FROM Account a WHERE a.name = :name")
public BigDecimal readAccountCreditLimits(#Param("name") String accountName);
}
------ and many more repositories as above

I ran into exactly the the same problem upgrading from 1.4.3 with hibernate 4.3.5. My repository interfaces extend PagingAndSortingRepository. I found the below line in Spring data change log for 1.6.0:
Can't use pagination (Pageable) with #IdClass entities (spring-data-jpa 1.4.3 & Hibernate 4.1.9). (DATAJPA-472)
(source: http://docs.spring.io/spring-data/jpa/docs/1.6.0.RELEASE/changelog.txt)
Replaced PagingAndSortingRepository with JpaRespository and seems to work fine.

After some research and many attempts, I found out the error was on my repository hierarchy.
So after improving my generics now it works as before.
From:
#Transactional(propagation = Propagation.MANDATORY)
public interface IBaseAddressRepository<T extends BaseEntity> extends IBaseRepository<T, Long> {
}
To:
#Transactional(propagation = Propagation.MANDATORY)
public interface IBaseAddressRepository<T extends Address> extends IBaseRepository<T, Long> {
}
Does anyone know if this is the expected behaviour? Although it's much better to narrow generic types as much as possible, my old repository should work too as long as Address extends BaseRepository, shouldn't it?

Spring Data tries to create an Implementation for your BaseRepository.
This requires an full Entity with #Entity, #Id.
It is possible to tell Spring that you don't need an Implemenation for the BaseRepository by adding the Annotation #NoRepositoryBean
This is how my "BaseRepository" looks like:
import java.io.Serializable;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.NoRepositoryBean;
#NoRepositoryBean
public interface IsActiveAwareRepository<T extends AbstractEntity, ID extends Serializable> extends CrudRepository<T, ID>{
public Iterable<T> findByIsActive(Boolean isActive);
}

Related

No property found for type in Spring custom query

I'm trying to implement a custom Spring repository. I have the interface:
public interface RataRepositoryCustom {
List<RataEntity> getRateFromTipoFrequenzaRimborso(String tipoFrequenzaRimborso);
}
where the RataEntity class is
#Entity
#Table(name = "rata")
public class RataEntity implements Serializable {
private static final long serialVersionUID = -4278591894832763005L;
#Id
#Column(name = "COD_RATA")
private Integer codRata;
#Column(name = "COD_RIMBORSO")
private String codRimborso;
#Column(name = "DATA_PROROGA")
private String dataProroga;
#Column(name = "PERC_CALCOLO")
private String percCalcolo;
#Column(name = "PERC_OUTSTANDING")
private String percOutstanding;
#Column(name = "DATA_SCADENZA")
private Date dataScadenza;
#Column(name = "IMPORTO_RATA")
private Double importoRata;
... getters and setters...
}
the implementation of it
#Repository
#Transactional(readOnly = true)
public class RateRepositoryCustomImpl implements RataRepositoryCustom {
#PersistenceContext
EntityManager entityManager;
#Override
public List<RataEntity> getRateFromTipoFrequenzaRimborso(String tipoFrequenzaRimborso) {
StringBuilder querySql = new StringBuilder();
querySql.append("SELECT distinct e FROM RataEntity e, RimborsoEntity r where e.codRimborso=r.codRimborso ");
if(tipoFrequenzaRimborso.equals("Ann"))
querySql.append("and r.freqRimborso='Annual'");
else if (tipoFrequenzaRimborso.equals("Sem"))
querySql.append("and r.freqRimborso='Semestral'");
else if (tipoFrequenzaRimborso.equals("Event"))
querySql.append("and r.freqRimborso='Ad event'");
Query query = entityManager.createQuery(querySql.toString());
return query.getResultList();
}
}
and the following repository class
#Repository public interface RataRepository extends JpaRepository<RataEntity, Integer>, RataRepositoryCustom {
}
When I run my application, I get this error:
Failed to create query for method public abstract java.util.List
it.aubay.PreliosPAN.repositories.RataRepositoryCustom.getRateFromTipoFrequenzaRimborso(java.lang.String)!
No property getRateFromTipoFrequenzaRimborso found for type
RataEntity!
It seems that Spring Framework tries to find a property with my method name in the Entity.
If I check the official documentation at this link
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-implementations
we have a generic example where the method name is
void someCustomMethod(User user)
I implemented the same code on other Entity objects and Spring Framework works properly with any method name. Only for the class of the example I have the error but I cannot understand why. Any idea?
I solved the problem.
The initial part of the name of the implementation class of the custom repository
RateRepositoryCustomImpl
is different from the name of the interface
RataRepositoryCustom
The correct name of the implementation class must be
RataRepositoryCustomImpl
Regards

No property [MethodName] found for type [EntityName] while executing custom jpa repository method

I've need to prepare a query in ServiceImpl ,as based on some logic the query can be differ by no. of columns. so I decided to prepare a custom JPA Repository but getting some error.
Before this to fulfill my requirement I tried this approach , please check .But I think JPA doesn't allow like this. So I tried Custom JPA Repository and getting error.
**
Entity class
#SuppressWarnings("serial")
#Entity
#Getter
#Setter
#Table(name = "REASON_CODE_REPORT",schema="automation")
#IdClass(ErrorCodeReportKeys.class)
public class ErrorCodeReportEntity
{
#Id
private String smsc;
#Id
private String userid;
#Id
private String smsc_userid;
#Id
private String operator;
#Id
private String circle;
#Id
private Date log_date;
#Id
private Integer log_hour;
#Id
private Integer log_min;
#Id
private Integer vf_reason_code;
#Id
private Integer smsc_reason_code;
private Integer count;
private Timestamp create_date;
}
**
ServiceImpl
#Override
public List<Object[]> errorCodeDefaultSummary(ErrorCodeReportDTO errorCodeReportDTO) {
String finalQuery="select smsc,userid from ErrorCodeReportEntity where log_date='2021-05-27'";
List<Object[]> result = errorCodeRepo.presentDaySummarySmscWise(finalQuery);
return result;
}
Custom JPA Interface
public interface ErrorCodeCustom {
List<Object[]> presentDaySummarySmscWise(String query);
}
Implementation of ErrorCodeCustomImpl
public class ErrorCodeCustomImpl implements ErrorCodeCustom{
#Autowired
private EntityManager entityManager;
#SuppressWarnings("unchecked")
#Override
public List<Object[]> presentDaySummarySmscWise(String query) {
final String finalQuery=query.toString();
List<Object[]> result= entityManager.createQuery(finalQuery).getResultList();
return result;
}
}
The Final Jpa Repository that implements our CustomRepository
#Repository
public interface ErrorCodeRepository extends JpaRepository<ErrorCodeReportEntity, ErrorCodeReportKeys>,ErrorCodeCustom
{
}
I don't know why i'm getting following errors
Caused by: java.lang.IllegalArgumentException: Failed to create query for method public abstract java.util.List com.valuefirst.repository.ErrorCodeCustom.presentDaySummarySmscWise(java.lang.String)! No property presentDaySummarySmscWise found for type ErrorCodeReportEntity!
Caused by: org.springframework.data.mapping.PropertyReferenceException: No property presentDaySummarySmscWise found for type ErrorCodeReportEntity!
Spring was not able to find your implementation ErrorCodeCustomImpl. You should annotate it #Component.
so the exception is there because ErrorCodeRepository extends ErrorCodeCustom and the query generated by your method name is trying to use a property named presentDaySummarySmscWise. Once your ErrorCodeCustomImpl will be injected by Spring the error will be gone.

~"IdClass not defined" in JpaRepository, for an inherited #OneToOne #Id

I'm trying to create a jpa repository but there is a problem with a foreign-key primary-key. Although it is specified in the abstract base class (MessageDestination), it seems to be invisible from the repository of specialized MessageDestination class (e.g. MessageDestinationRoom).
[...] nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'messageDestinationRoomDAO': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: This class [class com.chat.message.entity.MessageDestinationRoom] does not define an IdClass
#Entity #Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Message implements Serializable {
#Id #GeneratedValue(strategy = GenerationType.TABLE)
private Long id;
#OneToOne(targetEntity = MessageDestination.class,
cascade=CascadeType.ALL, mappedBy="msg")
#NotNull
private MessageDestination dest;
//...
}
#Entity #Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class MessageDestination implements Serializable {
#Id #OneToOne(cascade=CascadeType.ALL)
private Message msg;
}
#Entity
public class MessageDestinationRoom extends MessageDestination {
#OneToOne #NotNull
private Room destRoom;
//...
}
public interface MessageDestinationRoomDAO
extends JpaRepository<MessageDestinationRoom, Message> {
public Set<MessageDestinationRoom> findMessageDestinationRoomByDestRoom
(Room dest);
}
To solve the issue I saw that I can annotate MessageDestination as a #MappedSuperclass, but this can't work because it needs to be an #Entity to be stored in Message. Sadly, it's not possible:
org.hibernate.AnnotationException: An entity cannot be annotated with both #Entity and #MappedSuperclass
Any ideas? Thanks...
Since you are using table per class inheritance strategy and you dont have any mapped superclass (so each entity must have its own id).
You can annonate your MessageDestination Entity as #MappedSuperClass and remove the #Entity from MessageDestination. As by default its each subclass will inherited all its field including the #Id field
Pending for a better answer because the only solution I found is quite ugly. That consists of splitting the primary and the foreign key, so there is redundancy...
This:
#Entity #Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class MessageDestination implements Serializable {
#Id #OneToOne(cascade=CascadeType.ALL)
private Message msg;
}
public interface MessageDestinationRoomDAO
extends JpaRepository<MessageDestinationRoom, Message> {
public Set<MessageDestinationRoom> findMessageDestinationRoomByDestRoom
(Room dest);
}
becomes this:
#Entity #Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
abstract class MessageDestination implements Serializable {
#Id #GeneratedValue(strategy = GenerationType.TABLE)
private Long id;
#OneToOne(cascade=CascadeType.ALL)
private Message msg;
}
interface MessageDestinationRoomDAO
extends JpaRepository<MessageDestinationRoom, Long> {
public Set<MessageDestinationRoom> findMessageDestinationRoomByDestRoom
(Room dest);
}
I was also getting same issue when I was using #oneToMany And #ManyToOne Annotation based Mapping.
Basically what I was doing mistake was in the class that was throwing the error "does not define an IdClass" was having composite Keys i.e More that one #Id annotation used over two member variables due to which it was getting considered as Composite Key and since hibernate expects a seperate Key class needs to be defined in case of composite key this failure was coming.

Spring Data repository with generic as an entity type

I want to use Spring Data JPA repositories in my project. Usually I create my own repository, let's say
interface ProductRepository extends JPARepository<Product, Long>
However, I want to serve a bit more complex case that fits the following:
I have a basic entity with common definition:
#MappedSuperclass
public abstract class AbstractBaseEntity {
#GeneratedValue(strategy = GenerationType.AUTO)
#Id
#Column(name = "ID", nullable = false)
private Long id;
...
}
I have all other entities extending the above one, for example:
#Entity
#Table(name = "bread")
public class Bread extends AbstractBaseEntity {
#Column
String type;
...
}
and
#Entity
#Table(name = "butter")
public class Butter extends AbstractBaseEntity {
#Column
String weight;
...
}
I want that any repository that anyone creates, will only work with entities extending the AbstractBaseEntity. So I want to do something like this:
public interface MyBaseRepository<T> extends
JpaRepository<T extends AbstractBaseEntity, Long>
Then define a couple of common methods and then use it as follows:
public interface BreadRepository <Bread, Long> extends MyBaseRepository
or
public interface ButterRepository extends MyBaseRepository
The problem is that I cannot do this.
When I define MyBaseRepository, if I use:
MyBaseRepository<T extends AbstractBaseEntity> extends JpaRepository<T, Long>
I have an error that "entity does not have property type" when I running real query.
If I use just
extends JpaRepository
I get an error that Object is not mapped.
And if I try
JpaRepository<T extends AbstractBaseEntity , Long>
it just fails with unexpected binding error.
Do I miss anything or it is just not doable with Spring Data JPA?
Thanks!
I know this is an old thread but I had the same kind of error trying to define a repository like your MyBaseRepository<T extends AbstractBaseEntity> extends JpaRepository<T, Long>.
In my case the error was :
Failed to create query for method public abstract MyBaseRepository.someMethod(); Not an entity: AbstractBaseEntity
The point was that JPA was trying to implements all interfaces that extends JpaRepository and can't do it on MyBaseRepository<T> since <T> isn't a concrete class and AbstractBaseEntity not an #Entity.
The solution was to annotate MyBaseRepository<T> with #NoRepositoryBean to prevent JPA trying to implements this repository. And so, only your BreadRepository will be implemented.

How to call #NamedQueries from interface method definition?

I'm very new in Spring Framework, I want to know if is possible invoke Entity Named Query only defining the Named Query on the interface without any implementation.
I want to do something like this.
NamedQuery(name = "StateBo.findByCountry", query = "SELECT state FROM StateBo state WHERE state.country.id = ?")
#Table(name = "STATE")
#Entity(name = "StateBo")
public class StateBo extends BaseNamedBo {
private static final long serialVersionUID = 3687061742742506831L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "STATE_ID")
private Long id;
#Column(name = "ISO_CODE")
private String isoCode;
#ManyToOne
#JoinColumn(name = "COUNTRY_ID")
private CountryBo country;
// getters and setters ...
}
I defined the Named Query StateBo.findByBCountry, my interface looks like this
public interface IStateDao extends JpaRepository<StateBo, Long> {
public List<StateBo> findByCountry(Long id);
}
And the interface implementation looks like this.
#Transactional
#Repository("stateDao")
public class StateDao implements IStateDao {
}
But I have the error that I have to implement the methods that I'm defining on my interface, but I don't want to do that. I only want define my Named Query and define the method in my interface with the same name that is on the Entity and don't add the implementation of that method because the implementation is basically the String Named Query
You can use Spring Data Jpa project.
For start you see https://spring.io/guides/gs/accessing-data-jpa/
To execute query without an implementation(only interface) see http://docs.spring.io/spring-data/jpa/docs/1.6.0.RELEASE/reference/htmlsingle/#jpa.query-methods.at-query
Basically you don't need the implementation:
#Transactional
#Repository("stateDao")
public class StateDao implements IStateDao {
}
try to remove that and see what will happen.

Categories