How to resolve No converter found capable of converting from type TupleBackedMap to type [com.example.dto.ExampleDto] - spring-boot

org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [org.springframework.data.jpa.repository.query.AbstractJpaQuery$TupleConverter$TupleBackedMap] to type [com.example.dto.ExampleDto]
at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:321) ~[spring-core-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:194) ~[spring-core-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:174) ~[spring-core-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.data.repository.query.ResultProcessor$ProjectingConverter.convert(ResultProcessor.java:293) ~[spring-data-commons-2.1.5.RELEASE.jar:2.1.5.RELEASE]
The above error is being thrown when I have a query that returns 2 values in a native JPA query is being used. I'm capturing the query response in the DTO below:
#Data
#Entity
#NoArgsConstructor
#AllArgsConstructor
#Builder
public class ExampleDto {
#Id
private String name1;
private int nameFlag;
}
And in a DAO class, I'm calling the native query as below. The query works in SQL Developer and returns 2 records. But when called as below , it throws the above error.
List<ExampleDto> getExampleDto = myJPARepository.
.findNameObject(uuid);
There is something wrong in the DTO class, which i need to change. Annotations? I'm not sure what is missing here, and try as I might , putting in #Entity annotation, #Data annotation , I'm not able to resolve this error when the query is called.
UPDATE: The native query associated with this is
#Query(value = "select name1, nameFlag from NameTable",
nativeQuery = true, name = "findNameObject where namekey = ?")
List<ExampleDto> findNameObject(
#Param("nameKey") UUID nameKey);

This is a bug: https://jira.spring.io/browse/DATAJPA-1714
You can either use JPQL with a constructor expression, an interface projection or a custom method implementation as a workaround.

Make sure, your Repository class is using same class, as you are using for extracting the records from native query. Example shown below for XYZDTO
#Repository
public interface XYZRepository extends JpaRepository <XYZDTO, Long> {
}

Related

Using projection with a interface in `#Query` annotation with a native query gives "Target type is not an interface and no matching Converter found"

I have a table with a clob in an oracle 19 database which I try to fetch with a native query using a #Query annotation with a projection from a Spring boot 2.7.4 application. I get the following error message:
java.lang.UnsupportedOperationException: Cannot project jdk.proxy2.$Proxy281 implementing java.sql.Clob,org.hibernate.engine.jdbc.WrappedClob,java.io.Serializable to java.lang.String; Target type is not an interface and no matching Converter found
The query from my repository class:
#Query(
value = """
select submission_id as "submissionId", text as "textAnswer"
from answer
where answer_id = :answerId
""",
nativeQuery = true)
public MyDTO findDTO(Long answerId);
My interface which I use for the projection:
public interface MyDTO {
String getTextAnswer();
}
From my domain object annotated with #Entity:
private String textAnswer;
My testcase which reproduce which reproduce this error. If I comment out the line with a.getTextAnswer() it runs ok.
#Test
public void findFormPublishedAnswersInterfaceDTOById() {
FormPublishedAnswersInterfaceDTO a = answerRepository.findFormPublishedAnswersInterfaceDTOById(21540241L);
assertEquals("test", a.getTextAnswer());
}
I have tried different hints I found by the help of google :) like annotating private String textAnswer with #Lob, #Type(type = "text") and #Column(name = "text", columnDefinition = "CLOB") without any luck.
If you read the exception carefully, you should understand that the JDBC driver reports that the type is a Clob, so your DTO must look like this instead:
public interface MyDTO {
Clob getTextAnswer();
}

Spring Data JPA native query result binding

Entity class:
#Entity
#SqlResultSetMapping(
name="hourMapping",
classes=#ConstructorResult(
targetClass=Representation.class,
columns={
#ColumnResult(name="hour", type=BigDecimal.class),
#ColumnResult(name="transactions", type=BigDecimal.class)
}
)
)
#NamedNativeQuery(name="MyEntity.reportByHour", query="SELECT hour,SUM(tran_per_hour) AS transactions FROM MY_ENTITY GROUP BY hour ORDER BY hour"
,resultSetMapping="hourMapping")
#Table(name="MY_ENTITY")
public class MyEntity implements Serializable {
Pojo class:
#Data //Lombok
#JsonAutoDetect(fieldVisibility = Visibility.ANY)
public class Representation {
public Representation(BigDecimal hour, BigDecimal transactions) {
this.hour = hour;
this.transactions = transactions;
}
private BigDecimal hour;
private BigDecimal transactions;
Repository interface:
public interface MyEntityRepository extends JpaRepository<MyEntity, MyEntityPK> {
List<Representation> reportByHour();
}
When I run the endpoint which invokes the native query, I get exception:
Failed to convert from type [java.lang.Object[]] to type [com.representation.Representation] for value '{0, 198}'; nested exception is org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.math.BigDecimal] to type [com.representation.Representation]
Now if I just have "hour" field returned from my native query (and relevant changes to POJO constructor etc) it works fine.
Any help appreciated.
Ok, false alarm. My hibernate dependencies were all messed up and causing conflicts so resulting in the above exception.
After fixing these dependency issues, works great!!
Long story short: let spring-boot-* handle most hibernate dependencies instead of overriding or managing your own.

How to Define Dynamic Model in Spring Framework

I am using Spring Framework as my back end
I have define know as Entity class The Entity class know contain 5 Fields
Below is the class , The code below dose not have setter getter part to make shorter and cleaner
#Entity
#Table(name="TblKnow")
public class Know {
#Id
private Double idKnow;
private String SubjectKnow;
private String BodyKnow;
private String ImgKnow;
private double CountView;
In JpaRepository interface i want to only query two column not all of columns.
public interface KnowRepository extends JpaRepository<Know,Double> {
#Query("SELECT idKnow,SubjectKnow FROM Know")
public Page<Know> findCByOrderByIdKnowDesc(Pageable pageable);
Problem: i try to run but i get below exception
java.lang.IllegalArgumentException: Cannot create TypedQuery for query with more than one return using requested result type [java.lang.Long]
But if i use without below query it is fine
public Page<Know> findAllByOrderByIdKnowDesc(Pageable pageable);
You can create a custom constructor and use that to select only some fields in JPA query.
public Know(Double idKnow, String SubjectKnow) {
this.idKnow = idKnow;
this.SubjectKnow = SubjectKnow;
}
And the use this constructor in JPA query. Make sure you use complete path of class with package.
#Query("SELECT NEW packagePath.Know(idKnow,SubjectKnow) FROM Know")
query :
public Page<Know> findAllByOrderByIdKnowDesc(Pageable pageable);
works dut to you select Know objects with fields that are mapped correct into Know class (and after wrapped into Page).
with query :
#Query("SELECT idKnow,SubjectKnow FROM Know")
public Page<Know> findCByOrderByIdKnowDesc(Pageable pageable);
returns some custome bean/object that spring data can't map in correct way into Know class (as you declared it as expected return class wrapped into Page). add counstructor into Know with idKnow,SubjectKnow fields , or you can wrap it into some DTO with idKnow,SubjectKnow fields.

How to use projection interfaces with pagination in Spring Data JPA?

I'm trying to get a page of a partial entity (NetworkSimple) using the new feature of spring data, projections
I've checked the documentation and if I request only:
Collection<NetworkSimple> findAllProjectedBy();
It works, but if I'm using pageable:
Page<NetworkSimple> findAllProjectedBy(Pageable pageable);
It throws an error:
org.hibernate.jpa.criteria.expression.function.AggregationFunction$COUNT cannot be cast to org.hibernate.jpa.criteria.expression.CompoundSelectionImpl
Any one has already work with this ?
My NetworkSimple class is the following:
public interface NetworkSimple {
Long getId();
String getNetworkName();
Boolean getIsActive();
}
Note: This feature should work in the way described by the original poster but due to this bug it didn't. The bug has been fixed for the Hopper SR2 release, if you're stuck on an earlier version then the workaround below will work.
It is possible to use Pageable with the new query projection features introduced in Spring Data JPA 1.10 (Hopper). You will need to use the #Query annotation and manually write a query for the fields you require, they must also be aliased using AS to allow Spring Data to figure out how to project the results. There is a good example in spring-boot-samples part of the spring boot repository.
In your example it would be quite simple:
#Query("SELECT n.id AS id, n.name AS networkName, n.active AS isActive FROM Network n")
Page<NetworkSimple> findAllProjectedBy(Pageable pageable);
I have made the assumption that your entity looks something like this:
#Entity
public class Network
{
#Id
#GeneratedValue
private Long id;
#Column
private String name;
#Column
private boolean active;
...
}
Spring Data will derive a count query automatically for the paging information. It is also possible to make use of joins in the query to fetch associations and then summarise them in the projection.
I think you need create findAllProjectedBy() as specification.Then you can use findAll() method like this.
example :findAll(findAllProjectedBy(),pageable)
Following link may be help to find how to create specification in spring.
https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/
The issue may come from the method name. The by keyword means that you ae filterig data by a specific property: findByName for example. Its called query creation from method name:
http://docs.spring.io/spring-data/jpa/docs/1.10.1.RELEASE/reference/html/#repositories.query-methods.query-creation
So try with Page<NetworkSimple> findAll(Pageable pageable);
Even with spring-data-jpa 1.11.4, something like
public interface NetworkRepository extends JpaRepository<Network, String> {
Page<NetworkSimple> findAll(Pageable pageable);
}
would not compile; reporting
findAll(org.springframework.data.domain.Pageable) in NetworkRepository clashes with findAll(org.springframework.data.domain.Pageable) in org.springframework.data.repository.PagingAndSortingRepository
return type org.springframework.data.domain.Page<NetworkSimple> is not compatible with org.springframework.data.domain.Page<Network>
The workaround we found was to rename findAll to findAllBy, e.g.
public interface NetworkRepository extends JpaRepository<Network, String> {
Page<NetworkSimple> findAllBy(Pageable pageable);
}
You can use interface projection with Pageable like this :
Page<NetworkSimple> findPagedProjectedBy(Pageable pageable);
with some parameter :
Page<NetworkSimple> findPagedProjectedByName(String name, Pageable pageable);
Implementing interface projection with pagination
1. Our ResourceEntity.java class
#Getter
#Setter
#NoArgsConstructor
#Entity
public class ResourceEntity{
private Long id;
private String name;
}
2. Creating projection Interface name ProjectedResource.java, which maps data collected by the SQL query from repository layer method
public interface ProjectedResource {
Long getId();
String getName();
String getAnotherProperty();
}
3. Creating Repository layer method: getProjectedResources()
We are considering the database table name is resource.
We are only fetching id and name here.
#Query(name="select id, name, anotherProperty from resource", countQuery="select count(*) from resource", nativeQuery=true)
Page<ProjectedResource> getProjectedResources(Pageable page);
Hope the issue will be resolved!
You can use:
#Query("SELECT n FROM Network n")
Page<? extends NetworkSimple> findAllProjectedBy(Pageable pageable);

Spring data query where column is null

Suppose I have entities (getters/setters and various details omitted for brevity):
#Entity
class Customer{
...
#OneToMany(cascade = CascadeType.ALL, mappedBy = "customer")
Collection<Coupon> coupons;
}
#Entity
class Coupon{
...
#Temporal(value = TemporalType.TIMESTAMP)
private Date usedOn;
#ManyToOne(fetch = FetchType.LAZY)
#NotNull
Customer customer;
}
I wish retrieve all Coupons for a given Customer having null usedOn.
I,'ve unsuccessfully defined a method in the CouponRepository as described in docs
#Repository
public interface CouponRepository extends CrudRepository<Coupon, Long> {
Collection<Coupon> findByCustomerAndUsedOnIsNull(Customer);
}
but this leads on a compiler error Syntax error, insert "... VariableDeclaratorId" to complete FormalParameterList.
My fault, the correct definition is
#Repository
public interface CouponRepository extends CrudRepository<Coupon, Long> {
Collection<Coupon> findByCustomerAndUsedOnIsNull(Customer customer);
}
I simply missed the parameter name :-(
You can use IsNull to check null columns in JPA query.
For example for any columnA you can write query like query like
findByColumnAIsNull
In this case you can write queries like
#Repository
public interface CouponRepository extends CrudRepository<Coupon, Long> {
Collection<Coupon> findByCustomerAndUsedOnIsNull(Customer customer);
List<Coupon> findByUsedOnIsNull();
}
Also you can check how this queries will be
Refer this Spring Data JPA Query creation this will help you lot to understand and create different type of JPA query variation.
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation
Try changing your method to this (assuming Customer.id is a long):
Collection<Coupon> findByCustomer_IdAndUsedOnIsNull(Long customerId);
then use like this:
repo.findByCustomer_IdAndUsedOnIsNull(customer.getId());

Resources