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

Posted

技术标签:

【中文标题】没有找到能够从类型转换为类型的转换器【英文标题】:No converter found capable of converting from type to type 【发布时间】:2018-02-15 10:09:46 【问题描述】:

我得到以下堆栈跟踪:

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 

我的课如下

截止日期

@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") 格式的投影/映射无法正常工作可能是一个问题,因为这些是在类上而不是在接口上完成的???

【问题讨论】:

异常似乎没问题。 Classess 没有以任何方式连接(并且 JPA 引擎不知道 DeadlineType)。此代码是否正确粘贴?顺便说一句,导入 Lombok 项目(或代码中的注释),sn-ps 会更直观 - 不需要几秒钟的“这是什么” 这是 lombok @Value 还是 Spring @Value @Jacek Cz ,这是用于 JPA 和投影的 Spring 值。 嗨 Menelae,您能否确认您关于 @Value 和类而不是接口的假设是正确的?因为我面临类似的问题,我想使用已经在我的项目中许多地方声明和使用的类 DTO,所以我想避免引入新的接口。 与问题无关,但与实体上的 Lombok @Data 注释有关。这可能非常危险,因为它会根据您实体的所有字段(包括任何惰性关联)生成 equals、toString 和哈希码……因此,当您在事务之外使用实体并尝试将其打印出来或进行比较时到另一个,它将尝试获取所有那些惰性关联(在事务之外)并抛出一个 LazyInitializationException! 【参考方案1】:

从存储库返回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();

【讨论】:

难道我们没有使用projections 即时执行此操作的机制吗?至少那是一位同事提到的 @Valueannotations 的用途。 @MenelaosBakopoulos 查看更新的答案。文档:docs.spring.io/spring-data/rest/docs/current/reference/html/… 找不到任何@Projection 注释。 @seal,见spring-boot-starter-data-rest依赖 我会避免使用基于接口的投影,因为与基于类的投影相比,它们会消耗更多的内存。如果您的代码使用具有数千个结果的查询,例如在进行数据迁移时,那么内存消耗量就变得很重要。【参考方案2】:

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

Projection - 这将返回代码列两次,一次命名代码和命名文本(仅作为示例)。正如你上面所说,你不需要@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;

Repository - 您的存储库扩展了 JpaRepository 但 Id 是一个字符串,因此在下面更新为 JpaRepository

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

希望有帮助

莱斯

【讨论】:

你好莱斯威尔逊。这对于 Spring Data 已经准备好和管理的方法非常有效,例如“findAll”。但是,如果我需要使用 @Query 创建任何查询,则会发生以下错误: org.springframework.core.convert.ConverterNotFoundException: 找不到能够从类型转换的转换器。我设法通过仅使用接口而不是 DTO 创建带有“@”查询的东西来使用它。你知道是否可以创建我自己的“@”查询吗?谢谢。【参考方案3】:

简单的解决方案::

在查询中使用 nativeQuery=true。

例如

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

【讨论】:

【参考方案4】:

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

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

【讨论】:

【参考方案5】:

事实证明,当表名与模型名不同时,您必须将注释更改为:

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

而不是简单地使用@Entity 注解。

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

【讨论】:

【参考方案6】:

我最近在使用 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

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

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

【讨论】:

以上是关于没有找到能够从类型转换为类型的转换器的主要内容,如果未能解决你的问题,请参考以下文章

没有找到能够从类型 [java.lang.String] 转换为类型 [@Autowired @ManyToOne @JoinColumn com.papertrue.country.Country]

使用 GORM 获取 Mongo 集合时,找不到能够从 java.lang.Double 类型转换为 java.lang.Long 类型的转换器

Spring Boot Jpa 1.4.0 - 找不到能够从类型 [java.util.HashMap<?, ?>] 转换为 Pojo 类型的转换器

类型转换

如何在 Swift 中将 JSON 转换为数据类型?

C#如何把INT类型转换为方法参数对应的枚举类型?怎么强制转换?