未找到能够在类型之间转换的转换器



我得到以下堆栈跟踪:

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

默认 Id和文本

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

截止日期类型存储库

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

更新

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

从仓库返回ABDeadlineType

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

,然后转换为截止日期类型。手动或使用映射结构。

或者从@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();
}

您可能已经可以正常工作,但是 我创建了一个测试项目,其中包含以下类,允许您将数据检索到实体、投影或 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类 - 不确定为什么这是从基类继承然后重新定义属性。 Json属性只是如何更改传递回 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<ABDeadlineType,>Long>但 Id 是一个字符串,因此在下面更新为 JpaRepository<ABDeadlineType,>

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

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

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

简单的解决方案:

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

例如

@Query(value = "select d.id,d.name,d.breed,d.origin from Dog d",nativeQuery = true)

List<Dog> findALL();

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

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

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

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

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

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

如果您想使用DTO而不是列表中的实体,只需创建界面并将其替换为列表中的DTO即可。

例:

@Query(value = "select id, age, name FROM Person WHERE age=?1", nativeQuery=true)
List<PersonView> getPersonsByAge(int age);

和一个界面

public interface PersonView {
Long getId();
Integer getAge();
String getName();
}

好吧,我有另一个答案,我使用了投影接口和类 Dto和我正在使用ModelMapper将我的投影映射到Dto类 所以我的 1 Dto 类可能有很多投影可以映射到 Dto 并用于品尝

格拉德尔 实现 'org.modelmapper:modelmapper:3.1.0'

@Autowired
private ModelMapper modelMapper;

List<UserDto> usersdto = repository.findUserByRoleName().stream().map(userprojection -> modelMapper.map(userprojection, UserDto.class))
.collect(Collectors.toList());

我的投影是这样的

public interface UserProjection {
String getId();    
String getEmail(); 
}

我的 dto 是

@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserDto {
private long id;
private String firstName;
private String lastName;
private String phone;
private String email;
}

我能够从自定义查询中获取字段

将类名更改为DeadlineType

扩展 JpaRepository<class,类型>

例如:

在您的代码中,您放置查询的存储库扩展了 JpaRepository,其类和 id 类型为 <ABDeadlineType,>。因此,它期望返回 ABDeadlineType 数据。

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

当您想要获取DeadlineType数据时,您应该将查询保存在这样的存储库中,例如

public interface DeadlineTypeRepository extends JpaRepository<DeadlineType, Long>

因此,请替换 JpaRepository 中的类名<> 或者将您的查询放在另一个存储库中。然后,您无需对其进行任何映射或编写额外的代码。

就我而言,它奏效了。

对我来说,投影解决了这个问题,这里是代码段。 这是此示例的本机查询

SELECT cifno,accnbr FROM institutedb.customerWHERE id = 100200

步骤 1:首先创建与任何表相关的实体类

@Entity
@Table(name = "customer", schema = "institutedb")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class CustomerEntity {
@Id
private int id;
private BigInteger accnbr;
private String actdate;
private int active;
}

步骤2:然后清理投影接口和DTO类。 提醒接口getter方法应该有命名约定是DTO属性已经得到的。

投影接口

public interface CustomerProjection {
String getCifno();
String getAccnbr();
}

DTO类

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class CustomerDTO {
private String cifno;
private String accnbr;
}

第 3 步:

接下来创建存储库以嵌入本机查询

public interface CustomerModelReporsitoy  extends JpaRepository<CustomerEntity,String> {
@Query(
value = "SELECT cifno,accnbr FROM institutedb.customerWHERE id = 100200",
nativeQuery = true
)
List<CustomerProjection> findCifByUserName();
}

第 4 步:

创建用于测试目的的获取映射并访问存储库方法

@GetMapping("/custmodel")
public String getCifModel(){
ModelMapper modelMapper = new ModelMapper();
List<CustomerProjection> collect = customerModelReporsitoy.findCifByUserName().stream().map(customerProjection -> modelMapper.map(customerProjection, CustomerProjection.class))
.collect(Collectors.toList());
collect.stream().forEach((cust)-> {
System.out.println(cust.getCifno());
System.out.println(cust.getAccnbr());
});

return "cif";
}

最新更新