How to solve org.springframework.core.convert.ConversionFailedException while fetching the data from DB using spring data jpa - spring-boot

Domain Classes
#Data
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "SAMPLE_DATA")
#TypeDefs({
#TypeDef(name = "json", typeClass = JsonStringType.class),
#TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
})
public class Sample implements Serializable {
private static final long serialVersionUID = 1719868663566734198L;
#Id
private Long Id;
#Type(type = "json")
#Column(columnDefinition = "json",name = "person")
private Person personObj;
private String sampledata;
private String createdBy;
}
#Data
#NoArgsConstructor
#AllArgsConstructor
public class Person implements Serializable {
private static final long serialVersionUID = -5427425033242474312L;
private String firstName;
private String lastName;
}
Repository Class
#Repository
public interface SampleRepository extends JpaRepository<Sample, Long> {
#Query(value = "select s.personObj,s.sampledata from Sample s where s.Id=:Id")
List<Sample> findPersonById(Long Id);
}
To map to map JSON object types i m using
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-52</artifactId>
<version>${hibernate-types.version}</version>
</dependency>
when I am trying to fetch the list of Sample object I am getting the following exception
org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.Object[]] to type [#org.springframework.data.jpa.repository.Query com.domain.Sample] for value '[Person(firstName=abc, lastName=test)]'; nested exception is org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [com.domain.Person] to type [#org.springframework.data.jpa.repository.Query com.domain.Sample]
.........
Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [com.domain.Person] to type [#org.springframework.data.jpa.repository.Query com.domain.Sample]

You don't have to select the distinct columns. You must select the Entity:
#Repository
public interface SampleRepository extends JpaRepository<Sample, Long> {
#Query(value = "select s from Sample s where s.Id=:Id")
List<Sample> findPersonById(Long Id);
}

Related

No converter found capable of converting from type [java.math.BigInteger] to Entity

I'm trying to get a list of transactions from database and this is the error I'm facing.
"trace": "org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.Object[]] to type [com.wallet.sendmoney.entities.TransactionEntity] for value '{1, 1, null, null, KES, null, 123456, LQALVZCFJMU6, null, 2547XXXXXX3, 61234, Load wallet, null, null, null, null, null, WS322, null}'; nested exception is org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.math.BigInteger] to type [com.wallet.sendmoney.entities.TransactionEntity]
I'm using JPA #Query annotation and here is my repository
#Repository
public interface TransactionsRepository extends JpaRepository<LoadWalletEntity, Long> {
#Query(value = "SELECT * FROM transactions_attempts WHERE mobile_number= :mobile_number", nativeQuery = true)
List<TransactionEntity> getAllByPhoneNumber(#RequestParam String mobile_number);
}
Here is my entity class:
#Entity(name = "transactions_attempts")
#Table
#Data
#NoArgsConstructor
#AllArgsConstructor
public class LoadWalletEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String currency;
#Column(name = "mobile_number")
private String mobileNumber;
private String transactionRef;
private String merchantCode;
private Integer amount;
private String networkCode;
private String reason;
private String statusCode;
private String merchantReference;
private String merchantRequestId;
private String checkoutRequestId;
private Integer resultCode;
private String resultDescription;
private String billRefNumber;
private Date transactionDate;
#Column(name = "customer_mobile")
private String customerMobile;
private String thirdPartyTransId;
}
What could I be missing or doing wrong here.
Thanks in advance
you are trying to query a list of TransactionEntity
but your Repository is extends with
extends JpaRepository<LoadWalletEntity, Long> {
what's this LoadWalletEntity????
it should be
extends JpaRepository<TransactionEntity, Long> {
Try this solution please:
#Entity
#Table(name = "transactions_attempts")
instead of
#Entity(name = "transactions_attempts")
#Table

Can't access a property of a Embedded class via JPA

#Entity
#EntityListeners(AuditingEntityListener.class)
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "TIPO_CONTRATO", discriminatorType = DiscriminatorType.STRING)
#JsonIgnoreProperties({ "hibernateLazyInitializer", "handler" })
public class Contrato extends AuditorEntity implements Serializable, Clonable {
#Column(name = "CIF_NIF")
#JsonView(Views.Buscador.class)
#JsonProperty("cifNif")
private String cifNif;
#Column(name = "NOMBRE_SOCIEDAD_PERSONA")
#JsonView(Views.Buscador.class)
private String nombreSociedadPersona;
}
And i have this Embeddable class called CuentaBancaria from Contrato table:
#Embeddable
public class CuentaBancaria implements Serializable {
private static final long serialVersionUID = 6835775213299596371L;
#Column(name = "TITULAR_CUENTA")
#JsonView(Views.Completo.class)
private String titularCuenta;
}
In ContratoRepository i'm trying doing a JPA Query finding the "titularCuenta" field of Cuenta Bancaria finding by the cifNif field of Contrato. But it's not working. What can i do to solve this?
#Query(value="SELECT c.CuentaBancaria.titularCuenta FROM Contrato c WHERE c.cifNif= ?1 AND c.nombreSociedadPersona IS NOT NULL AND ROWNUM = 1")
public String getNombreLegalCliente(String cifNif);
The error which is throwing:
Caused by: org.hibernate.QueryException: could not resolve property:
CuentaBancaria of: com.xxxx.Contrato
You're missing CuentaBancaria field in Contrato class. That's why JQL complains.
Add the field in the class with #Embedded annotation:
public class Contrato extends AuditorEntity implements Serializable, Clonable {
#Embedded
private CuentaBancaria cuentaBancaria;
}
And fix the JQL expression to:
#Query(value="SELECT c.cuentaBancaria.titularCuenta FROM Contrato c WHERE c.cifNif= ?1 AND c.nombreSociedadPersona IS NOT NULL AND ROWNUM = 1")
public String getNombreLegalCliente(String cifNif);
Yes, since your class [ CuentaBancaria ] is annotated with #Embeddable, it needs to be embedded in the parent class in this case [ Contrato ] with #Embedded.
Then, harnessing Spring Data JPA query Lookup strategies, you can access property fields of your embedded class with ease or you could still go by the #Query() approach
Query lookup Strategy from Spring documentation
Sample demo code with your problem with a minimal implementation:
Entity-Class
--------------
#Entity
public class Contrato{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long contratoId;
#Column(name = "CIF_NIF")
private String cifNif;
#Column(name = "NOMBRE_SOCIEDAD_PERSONA")
private String nombreSociedadPersona;
//we call the embeddable class in this parent class with #Embedded annotation
#Embedded
private CuentaBancaria cuentaBancaria
}
Embeddable-Class
-----------------
#Embeddable
public class CuentaBancaria{
#Column(name = "TITULAR_CUENTA")
private String titularCuenta;
}
Now in your ContratoRepository class, we could have
#Repository
public interface ContratoRepository extends CrudRepository<Contrato, Long> {
Optional<Contrato> findByCuentaBancariaTitularCuenta(String cifNif);
}
which interprets to JPQL snippet:
c.cuentaBancaria.titularCuenta FROM Contrato c WHERE c.cifNif= ?1
NOTE: Notice the query method name matches the exact names in the classes and their corresponding fields, preceded by findBy

Spring data JPA: embedded ID error when saving the entity

I have the following entity classes:
#Embeddable
#Getter
#Setter
public class OrganizationCyclePlageKey implements Serializable {
#Column(name = "organization_id")
Long organizationId;
#Column(name = "cycle_plages_id")
Long cyclePlagesId;
...
equals() and hashCode() methods come here
#Entity
#Table(name = "organization_cycle_plages")
#Getter
#Setter
public class OrganizationCyclePlage {
#EmbeddedId
private OrganizationCyclePlageKey id;
#ManyToOne
#MapsId("organizationId")
#JoinColumn(name = "organization_id")
Organization organization;
#ManyToOne
#MapsId("cyclePlagesId")
#JoinColumn(name = "cycle_plages_id")
CyclePlage cyclePlage;
...
other attributes
}
#Entity
#Getter
#Setter
public class CyclePlage extends AbstractEntity {
#OneToMany(mappedBy = "cyclePlage")
private Set<OrganizationCyclePlage> organizationCyclePlages;
...
}
#Entity
#DynamicUpdate
#Getter
#Setter
public class Organization extends AbstractEntity {
#OneToMany(mappedBy = "organization")
private Set<OrganizationCyclePlage> organizationCyclePlages = new HashSet<>();
...
}
SpringBoot app starts up normally without errors.
But when I try to save an instance of OrganizationCyclePlage:
OrganizationCyclePlage ocp = new OrganizationCyclePlage();
ocp.setOrganization(organization);
ocp.setCyclePlage(cyclePlage);
organizationCyclePlageRepository.save(ocp);
it raises the error when calling organizationCyclePlageRepository.save(ocp):
org.hibernate.PropertyAccessException: Could not set field value [361] value by reflection : [class com.XXXX.OrganizationCyclePlageKey.cyclePlagesId] setter of com.XXXX.OrganizationCyclePlageKey.cyclePlagesId
What's wrong with these relations?
I had to add the constructor into the OrganizationCyclePlageKey class to init the foreign keys values as well a default constructor via #NoArgsConstructor annotation:
public OrganizationCyclePlageKey(Long organizationId, Long cyclePlagesId) {
this.organizationId = organizationId;
this.cyclePlagesId = cyclePlagesId;
}
and init the OrganizationCyclePlageKey instance in the OrganizationCyclePlage class:
public class OrganizationCyclePlage {
private OrganizationCyclePlageKey id = new OrganizationCyclePlageKey();
...
}

Why is my mapped DTO List null? What is the best way to map and persist Child Lists?

I have a simple problem - but I think "I am standing on the tube".
I have a spring boot rest api with JPA, Modelmapper, Entities and DTOs.
But the mapping doesn't work.
Entities:
#Getter
#Setter
#MappedSuperclass
public class AbstractEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}
#Getter
#Setter
#Entity(name = "contacts")
public class Contact extends AbstractEntity {
#NotBlank
private String firstName;
#NotBlank
private String lastName;
#Valid
#OneToMany(mappedBy = "contact", cascade = CascadeType.ALL, orphanRemoval = true)
private List<PhoneNumber> phoneNumberList;
}
#Getter
#Setter
#Entity(name = "phone_numbers")
public class PhoneNumber extends AbstractEntity {
#NotBlank
private String label;
#NotBlank
private String number;
#ManyToOne
#JoinColumn(name = "contact_id", referencedColumnName = "id")
#Setter(value = AccessLevel.NONE)
private Contact contact;
}
The DTOs:
#Getter
#Setter
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class ContactDTO {
private Long id;
private String firstName;
private String lastName;
List<PhoneNumberDTO> phoneNumberDTOList = new ArrayList<>();
}
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class PhoneNumberDTO {
private Long id;
private String label;
private String number;
}
My ModelMapperConfig:
#Bean
public ModelMapper modelMapper() {
ModelMapper modelMapper = new ModelMapper();
modelMapper.getConfiguration()
.setFieldMatchingEnabled(true)
.setFieldAccessLevel(AccessLevel.PRIVATE);
return modelMapper;
}
Repo:
public interface ContactRepository extends JpaRepository<Contact, Long{
}
Service (only the create method):
#Override
public ContactDTO createOne(ContactDTO contactDTO) {
Contact contact = modelMapper.map(contactDTO, Contact.class);
contactRepository.save(contact);
return contactDTO;
}
Is this the correct way to persist the Contact with its multiple phonenumbers?
And how can I create a simple mapping?
If i want to persist it, there comes an error:
Column 'contact_id' cannot be null

How to join multiple queryDSL tables

I have some tables and I want to get result using queryDSL join, but haven't found any examples on multiple joins using queryDSL.
I have these tables:
Account table: accountId (PK) | email | password
account_profile table: accountId (PK)(fk to account) | nickname
Community table: articleId (PK) | accountId (fk to account) | title | content
Now I want below JPQL to be queryDSL code
select r from community r join r.account.profile a where a.nickname = :nickname
I have entity metamodels - QAccount, QAccountProfile, QCommunity
Additionally, I have to get the result with pagination, so the query should be called with pageable object.
Here is my work that doesn't work yet.
JPAQuery</*What generic type expected?*/> query = new JPAQuery</*???*/>(entityManager);
Predicate predicate = query.from(QCommunity.community).join(/*join directly accountProfile? or account? is it QEntity or real entity?*/);
// where should I place nickname matching condition ?
...
list = (repository.findAll(predicate, pageable)).getContent();
Where should I place the nickname matching condition?
EDIT: Appended entity information
Account.java
#Entity
#Table(name="account", uniqueConstraints={
#UniqueConstraint(columnNames="account_seq"),
#UniqueConstraint(columnNames="email")
})
#DynamicInsert
#DynamicUpdate
#Data
#EqualsAndHashCode
#ToString(includeFieldNames=true)
#RequiredArgsConstructor(staticName="of")
#NoArgsConstructor
public class Account implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="account_seq", nullable=false, unique=true)
private Integer accountId;
#Column(name="email", nullable=false, unique=true)
#NonNull
private String email;
#NonNull
private String password;
#OneToOne(cascade=CascadeType.ALL, mappedBy="account")
private AccountProfile profile;
#OneToOne(cascade=CascadeType.ALL, mappedBy="account")
private AccountSecurity security;
}
AccountProfile.java
#Entity
#Table(name="account_profile", uniqueConstraints={
#UniqueConstraint(columnNames={"account_seq"}),
#UniqueConstraint(columnNames={"nickname"})
})
#DynamicInsert
#DynamicUpdate
#Data
#EqualsAndHashCode
#ToString(includeFieldNames=true)
#RequiredArgsConstructor(staticName="of")
#NoArgsConstructor
public class AccountProfile implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name="account_seq", referencedColumnName="account_seq")
private Account account;
#Column(name="nickname", nullable=false)
#NonNull
private String nickname;
}
Community.java
#Entity
#Table(name="community", uniqueConstraints = {
#UniqueConstraint(columnNames="article_seq")
})
#DynamicInsert
#DynamicUpdate
#Data
#NoArgsConstructor
#EqualsAndHashCode
#ToString(includeFieldNames=true)
public class Community {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="article_seq", nullable=false, unique=true)
private Long articleId;
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name="account_seq", referencedColumnName="account_seq")
private Account account;
#Column(name="title", nullable=false)
private String title;
#Column(name="content", nullable=false)
private String content;
#Temporal(TemporalType.TIMESTAMP)
#Column(name="reg_dt")
private Date date;
#Column(name="read_cnt", nullable=false)
private int readCount;
#Column(name="attach_url")
private String attachUrl;
#Column(name="attach_filename")
private String attachFileName;
#OneToMany(cascade=CascadeType.ALL, mappedBy="article")
private Set<CommunityReply> replies;
}
EDIT: PROBLEM SOLVED
To help others who is facing the problem like me, I am gonna post my working code. the code is searching any community articles with matching specific nickname.
#PersistenceContext
private EntityManager entityManager;
private List<Community> getList(int pageNo, String keyword, int rowsOnPage){
int offset = (pageNo -1) * rowsOnPage;
int limit = rowsOnPage;
JPAQuery<Community> query = new JPAQuery<Community>(entityManager);
QCommunity qCommunity = QCommunity.community;
QAccount qAccount = QAccount.account;
QAccountProfile qAccountProfile = QAccountProfile.accountProfile;
return query
.from(qCommunity)
.innerJoin(qCommunity.account ,qAccount)
.innerJoin(qAccount.profile, qAccountProfile)
.where(qAccountProfile.nickname.like("%"+keyword+"%"))
.orderBy(qCommunity.articleId.desc())
.offset(offset)
.limit(limit)
.fetch();
}
First of all, declare a custom extended base repository class for QueryDSL queries.
First the interface:
#NoRepositoryBean
public interface ExtendedQueryDslJpaRepository<T, ID extends Serializable>
extends JpaRepository<T, ID>, QueryDslPredicateExecutor<T> {
<T1> Page<T1> findAll(JPQLQuery jpqlQuery, Pageable pageable);
}
And then the implementation:
public class ExtendedQueryDslJpaRepositoryImpl<T, ID extends Serializable>
extends QueryDslJpaRepository<T, ID> implements ExtendedQueryDslJpaRepository<T, ID> {
private static final EntityPathResolver DEFAULT_ENTITY_PATH_RESOLVER = SimpleEntityPathResolver.INSTANCE;
private final EntityPath<T> path;
private final PathBuilder<T> builder;
private final Querydsl querydsl;
private EntityManager entityManager;
public ExtendedQueryDslJpaRepositoryImpl(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager) {
this(entityInformation, entityManager, DEFAULT_ENTITY_PATH_RESOLVER);
}
public ExtendedQueryDslJpaRepositoryImpl(JpaEntityInformation<T, ID> entityInformation,
EntityManager entityManager, EntityPathResolver resolver) {
super(entityInformation, entityManager);
this.path = resolver.createPath(entityInformation.getJavaType());
this.builder = new PathBuilder(this.path.getType(), this.path.getMetadata());
this.querydsl = new Querydsl(entityManager, this.builder);
this.entityManager = entityManager;
}
#Override
public <T1> Page<T1> findAll(JPQLQuery jpqlQuery, Pageable pageable) {
// Count query
final JPQLQuery<?> countQuery = jpqlQuery;
// Apply pagination
JPQLQuery<T1> query = querydsl.applyPagination(pageable, jpqlQuery);
// Run query
return PageableExecutionUtils.getPage(query.fetch(), pageable, countQuery::fetchCount);
}
}
Define the new class as base for base and repositories in a #Configuration class.
#Configuration
#EnableJpaRepositories(basePackageClasses = ..., repositoryBaseClass = ExtendedQueryDslJpaRepositoryImpl.class)
Your repositories then should extend from the new interface (which of course extends JpaRepository):
#Repository
public interface CommunityRepository extends ExtendedQueryDslJpaRepository<Community, Long> {
}
Then, you can try the following code:
String nickname = "nick";
QAccount account = QAccount.account;
QAccountProfile accountProfile = QAccountProfile.accountProfile;
QCommunity community = QCommunity.community;
JPQLQuery query = new JPAQuery(entityManager);
BooleanBuilder predicate = new BooleanBuilder();
predicate.and(accountProfile.nickname.eq(nickname));
// select r from community r join r.account.profile a where a.nickname = :nickname
query.from(community)
.join(community.account, account)
.join(account.accountProfile, accountProfile)
.where(predicate);
repository.findAll(query, pageable);
Hope that helps.
I found one solution as
QEntity qEntity1 = new QEntity("qEntity1");
QEntity qEntity2 = new QEntity("qEntity2");
so while querying you can use
new JPAQueryFactory(entityManager).from(qSampleBO)
.innerJoin(qEntity1).on(qEntity1.id.eq(qSampleBO.address.id))
.innerJoin(qEntity2).on(qEntity2.id.eq(qSampleBO.secondary_address.id))
...

Resources