No converter found capable of converting from type to type

SpringJpaSpring Data-JpaConverter

Spring Problem Overview


I am getting the following stacktrace:

org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [referencedata.ABDeadlineType] to type [referencedata.DeadlineType]
	at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:324)
	at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:206)
	at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:187)
	at org.springframework.data.repository.query.ResultProcessor$ProjectingConverter.convert(ResultProcessor.java:256)
	at org.springframework.data.repository.query.ResultProcessor$ChainingConverter$1.convert(ResultProcessor.java:201)
	at org.springframework.data.repository.query.ResultProcessor$ChainingConverter.convert(ResultProcessor.java:212)
	at org.springframework.data.repository.query.ResultProcessor.processResult(ResultProcessor.java:149)
	at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:121)
	at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:106)
	at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:483)
	at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:461)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:56)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
	at com.sun.proxy.$Proxy143.findAllSummarizedBy(Unknown Source)
	at 

My classes are the following

DeadlineType

@Data
public class DeadlineType extends DefaultIdAndText {
    @Value("#{target.id}")
    String id;

    @Value("#{target.code}")
    String text;

    @Value("#{target.id}")
    public String getId() {
        return id;
    }

    @Value("#{target.code}")
    public String getText() {
        return text;
    }

}

ABDeadlineType

@Data
@Entity
@Table(name = "deadline_type")
@AllArgsConstructor
@NoArgsConstructor
public class ABDeadlineType {

    private @Id
    String id;
    private String code;
}

DefaultIdAndText

@Data @AllArgsConstructor
@NoArgsConstructor
public class DefaultIdAndText implements IdAndText {

	public DefaultIdAndText(IdAndText idAndText){
		this.id = idAndText.getId();
		this.text = idAndText.getText();
	}

	@NotEmpty String id;
	String text;
}

DeadlineTypeRepository

public interface DeadlineTypeRepository extends JpaRepository<ABDeadlineType, Long> {
    List<DeadlineType> findAllSummarizedBy();
}

Update

Could it be an issue that the projection/mapping using @Value("#{target.id}") format, does not work correctly because these have been done on a class and not on an interface???

Spring Solutions


Solution 1 - Spring

Return ABDeadlineType from repository:

public interface ABDeadlineTypeRepository extends JpaRepository<ABDeadlineType, Long> {
    List<ABDeadlineType> findAllSummarizedBy();
}

and then convert to DeadlineType. Manually or use mapstruct.

Or call constructor from @Query annotation:

public interface DeadlineTypeRepository extends JpaRepository<ABDeadlineType, Long> {

    @Query("select new package.DeadlineType(a.id, a.code) from ABDeadlineType a ")
    List<DeadlineType> findAllSummarizedBy();
}

Or use @Projection:

@Projection(name = "deadline", types = { ABDeadlineType.class })
public interface DeadlineType {

    @Value("#{target.id}")
    String getId();

    @Value("#{target.code}")
    String getText();

}

Update: Spring can work without @Projection annotation:

public interface DeadlineType {
    String getId();    
    String getText();
}

Solution 2 - Spring

You may already have this working, but the I created a test project with the classes below allowing you to retrieve the data into an entity, projection or dto.

Projection - this will return the code column twice, once named code and also named text (for example only). As you say above, you don't need the @Projection annotation

import org.springframework.beans.factory.annotation.Value;

public interface DeadlineTypeProjection {
    String getId();

    // can get code and or change name of getter below
    String getCode();

    // Points to the code attribute of entity class
    @Value(value = "#{target.code}")
    String getText();
}

DTO class - not sure why this was inheriting from your base class and then redefining the attributes. JsonProperty just an example of how you'd change the name of the field passed back to a REST end point

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class DeadlineType {
    String id;

    // Use this annotation if you need to change the name of the property that is passed back from controller
    // Needs to be called code to be used in Repository
    @JsonProperty(value = "text")
    String code;

}

Entity class

import lombok.Data;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Data
@Entity
@Table(name = "deadline_type")
public class ABDeadlineType {

    @Id
    private String id;
    private String code;
}

Repository - your repository extends JpaRepository<ABDeadlineType, Long> but the Id is a String, so updated below to JpaRepository<ABDeadlineType, String>

import com.example.demo.entity.ABDeadlineType;
import com.example.demo.projection.DeadlineTypeProjection;
import com.example.demo.transfer.DeadlineType;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface ABDeadlineTypeRepository extends JpaRepository<ABDeadlineType, String> {

    List<ABDeadlineType> findAll();

    List<DeadlineType> findAllDtoBy();

    List<DeadlineTypeProjection> findAllProjectionBy();

}

Example Controller - accesses the repository directly to simplify code

@RequestMapping(value = "deadlinetype")
@RestController
public class DeadlineTypeController {

    private final ABDeadlineTypeRepository abDeadlineTypeRepository;

    @Autowired
    public DeadlineTypeController(ABDeadlineTypeRepository abDeadlineTypeRepository) {
        this.abDeadlineTypeRepository = abDeadlineTypeRepository;
    }

    @GetMapping(value = "/list")
    public ResponseEntity<List<ABDeadlineType>> list() {

        List<ABDeadlineType> types = abDeadlineTypeRepository.findAll();
        return ResponseEntity.ok(types);
    }

    @GetMapping(value = "/listdto")
    public ResponseEntity<List<DeadlineType>> listDto() {

        List<DeadlineType> types = abDeadlineTypeRepository.findAllDtoBy();
        return ResponseEntity.ok(types);
    }

    @GetMapping(value = "/listprojection")
    public ResponseEntity<List<DeadlineTypeProjection>> listProjection() {

        List<DeadlineTypeProjection> types = abDeadlineTypeRepository.findAllProjectionBy();
        return ResponseEntity.ok(types);
    }
}

Hope that helps

Les

Solution 3 - Spring

Turns out, when the table name is different than the model name, you have to change the annotations to:

@Entity
@Table(name = "table_name")
class WhateverNameYouWant {
    ...

Instead of simply using the @Entity annotation.

What was weird for me, is that the class it was trying to convert to didn't exist. This worked for me.

Solution 4 - Spring

Simple Solution::

use {nativeQuery=true} in your query.

for example

  @Query(value = "select d.id,d.name,d.breed,d.origin from Dog d",nativeQuery = true)
        
    List<Dog> findALL();

Solution 5 - Spring

If you look at the exception stack trace it says that, it failed to convert from ABDeadlineType to DeadlineType. Because your repository is going to return you the objects of ABDeadlineType. How the spring-data-jpa will convert into the other one(DeadlineType). You should return the same type from repository and then have some intermediate util class to convert it into your model class.

public interface ABDeadlineTypeRepository extends JpaRepository<ABDeadlineType, Long> {
    List<ABDeadlineType> findAllSummarizedBy();
}

Solution 6 - Spring

I have met the same problem recently with spring-data-jpa:2.5.0.

Solution (for queries with no @Query annotation):

For class-based projection (DTOs), the problem is the @NoArgsConstructor in the DTO class. Revemoving it should make things work.

Something interesting I found during debug:

With the presence of a non argument constructor, the returnedType somehow was created with 0 input properties.

When a query is actually created, JpaQueryCreator (spring-data-jpa) would check if it needs to do custom construction according to the number of input properties.

As it's not the case with 0 input properties, it would then return the whole entity instance.

https://github.com/spring-projects/spring-data-jpa/blob/main/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryCreator.java#L169

Finally when the result is being returned, the target type and returned type don't match, as there is no converter available to convert from the entity instance to the projectiong dto. The error was thrown.

https://github.com/spring-projects/spring-data-commons/blob/main/src/main/java/org/springframework/data/repository/query/ResultProcessor.java#L162

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMenelaosView Question on Stackoverflow
Solution 1 - SpringNickView Answer on Stackoverflow
Solution 2 - SpringLes WilsonView Answer on Stackoverflow
Solution 3 - SpringGeorgeView Answer on Stackoverflow
Solution 4 - SpringDeVView Answer on Stackoverflow
Solution 5 - SpringSangam BeloseView Answer on Stackoverflow
Solution 6 - SpringYing CherryView Answer on Stackoverflow