找不到能够从类型转换为类型的转换器
No converter found capable of converting from type to type
我得到以下堆栈跟踪:
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.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.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
我的class如下
截止日期类型
@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}")
格式的 projection/mapping 无法正常工作可能是个问题,因为这些是在 class 而不是接口上完成的???
Return 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();
}
如果您查看异常堆栈跟踪,它会说无法从 ABDeadlineType
转换为 DeadlineType
。因为您的存储库将 return 您 ABDeadlineType
的对象。 spring-data-jpa
将如何转换为另一个 (DeadlineType
)。您应该 return 来自存储库的相同类型,然后使用一些中间工具 class 将其转换为您的模型 class.
public interface ABDeadlineTypeRepository extends JpaRepository<ABDeadlineType, Long> {
List<ABDeadlineType> findAllSummarizedBy();
}
你可能已经有了这个工作,但我用下面的 classes 创建了一个测试项目,允许你将数据检索到实体、投影或 dto 中。
Projection - 这将 return 代码列两次,一次命名代码,一次命名文本(仅供示例)。正如你上面所说,你不需要@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 class - 不确定为什么这是从您的基 class 继承然后重新定义属性。 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;
}
实体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 - 您的存储库扩展了 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);
}
}
希望对您有所帮助
莱斯
事实证明,当 table 名称与模型名称 不同时,您必须将注释更改为:
@Entity
@Table(name = "table_name")
class WhateverNameYouWant {
...
而不是简单地使用@Entity 注释。
对我来说很奇怪的是,它试图转换成的 class 并不存在。这对我有用。
简单的解决方案::
在您的查询中使用 {nativeQuery=true}。
例如
@Query(value = "select d.id,d.name,d.breed,d.origin from Dog d",nativeQuery = true)
List<Dog> findALL();
我最近遇到了同样的问题 spring-data-jpa:2.5.0.
解决方法(针对没有@Query注解的查询):
对于基于 class 的投影 (DTO),问题是 DTO class 中的 @NoArgsConstructor
。删除它应该可以正常工作。
我在调试过程中发现了一些有趣的东西:
由于存在非参数构造函数,returnedType
以某种方式创建了 0 个输入属性。
真正创建查询时,JpaQueryCreator
(spring-data-jpa)会根据输入属性的个数判断是否需要自定义构建
由于输入属性不是 0,因此它会 return 整个实体实例。
最后,当结果被 returned 时,目标类型和 returned 类型不匹配,因为没有转换器可用于从实体实例转换为投影 dto .抛出错误。
我得到以下堆栈跟踪:
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.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.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
我的class如下
截止日期类型
@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}")
格式的 projection/mapping 无法正常工作可能是个问题,因为这些是在 class 而不是接口上完成的???
Return 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();
}
如果您查看异常堆栈跟踪,它会说无法从 ABDeadlineType
转换为 DeadlineType
。因为您的存储库将 return 您 ABDeadlineType
的对象。 spring-data-jpa
将如何转换为另一个 (DeadlineType
)。您应该 return 来自存储库的相同类型,然后使用一些中间工具 class 将其转换为您的模型 class.
public interface ABDeadlineTypeRepository extends JpaRepository<ABDeadlineType, Long> {
List<ABDeadlineType> findAllSummarizedBy();
}
你可能已经有了这个工作,但我用下面的 classes 创建了一个测试项目,允许你将数据检索到实体、投影或 dto 中。
Projection - 这将 return 代码列两次,一次命名代码,一次命名文本(仅供示例)。正如你上面所说,你不需要@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 class - 不确定为什么这是从您的基 class 继承然后重新定义属性。 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;
}
实体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 - 您的存储库扩展了 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);
}
}
希望对您有所帮助
莱斯
事实证明,当 table 名称与模型名称 不同时,您必须将注释更改为:
@Entity
@Table(name = "table_name")
class WhateverNameYouWant {
...
而不是简单地使用@Entity 注释。
对我来说很奇怪的是,它试图转换成的 class 并不存在。这对我有用。
简单的解决方案::
在您的查询中使用 {nativeQuery=true}。
例如
@Query(value = "select d.id,d.name,d.breed,d.origin from Dog d",nativeQuery = true)
List<Dog> findALL();
我最近遇到了同样的问题 spring-data-jpa:2.5.0.
解决方法(针对没有@Query注解的查询):
对于基于 class 的投影 (DTO),问题是 DTO class 中的 @NoArgsConstructor
。删除它应该可以正常工作。
我在调试过程中发现了一些有趣的东西:
由于存在非参数构造函数,returnedType
以某种方式创建了 0 个输入属性。
真正创建查询时,JpaQueryCreator
(spring-data-jpa)会根据输入属性的个数判断是否需要自定义构建
由于输入属性不是 0,因此它会 return 整个实体实例。
最后,当结果被 returned 时,目标类型和 returned 类型不匹配,因为没有转换器可用于从实体实例转换为投影 dto .抛出错误。