没有找到能够从类型转换为类型的转换器

时间:2017-09-06 19:52:31

标签: spring jpa spring-data-jpa converter

我得到以下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 

我的课程如下

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();
}

更新

使用@Value("#{target.id}")格式的投影/映射无法正常工作,因为这些是在类而不是在接口上完成的吗?

6 个答案:

答案 0 :(得分:18)

从存储库返回ABDeadlineType

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

然后转换为DeadlineType。手动或使用mapstruct。

或者从@Query注释中调用构造函数:

public interface DeadlineTypeRepository extends JpaRepository<ABDeadlineType, Long> {

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

或使用@Projection

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

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

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

}

<强>更新 Spring可以在没有@Projection注释的情况下工作:

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

答案 1 :(得分:2)

简单解决方案::

在查询中使用{nativeQuery = true}。

例如

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

答案 2 :(得分:1)

如果你看一下它说的异常堆栈跟踪,它就无法从ABDeadlineType转换为DeadlineType。因为您的存储库将返回ABDeadlineType的对象。 spring-data-jpa如何转换为另一个(DeadlineType)。您应该从存储库返回相同的类型,然后使用一些中间的util类将其转换为您的模型类。

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

答案 3 :(得分:1)

您可能已经有了这个工作,但我创建了一个包含以下类的测试项目,允许您将数据检索到实体,投影或dto。

投影 - 这将返回代码列两次,一次命名代码并命名为文本(仅限示例)。如上所述,您不需要@Projection注释

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类 - 不确定为什么这是从您的基类继承然后重新定义属性。 JsonProperty只是一个例子,说明如何更改传递回REST端点的字段名称

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;

}

实体类

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;
}

存储库 - 您的存储库扩展了JpaRepository&lt; ABDeadlineType,Long&gt;但Id是一个字符串,因此在下面更新为JpaRepository&lt; ABDeadlineType,String&gt;

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();

}

示例控制器 - 直接访问存储库以简化代码

@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);
    }
}

希望有所帮助

莱斯

答案 4 :(得分:1)

结果是,当表名称不同于模型名称时,您必须将注释更改为:

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

不仅仅是使用@Entity批注。

对我来说奇怪的是,它试图转换为的类不存在。这对我有用。

答案 5 :(得分:0)

我最近在使用 spring-data-jpa:2.5.0 时遇到了同样的问题。

解决方案(针对没有@Query 注释的查询):

对于基于类的投影 (DTO),问题在于 DTO 类中的 @NoArgsConstructor。删除它应该可以使事情发挥作用。

我在调试过程中发现了一些有趣的东西:

由于存在非参数构造函数,returnedType 以某种方式使用 0 个输入属性创建。

当实际创建查询时,JpaQueryCreator (spring-data-jpa) 会根据输入属性的数量检查是否需要进行自定义构造。

因为它不是 0 个输入属性的情况,所以它会返回整个实体实例。

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

最后返回结果时,目标类型和返回类型不匹配,因为没有转换器可用于从实体实例转换为投影。错误被抛出。

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