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

我得到了以下堆栈跟踪:

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}")格式的投影/映射不能正常工作,是否可能是因为这些已经在类上而不是在接口上完成了? ? ?

253386 次浏览

从存储库返回 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。因为存储库将返回 ABDeadlineType的对象。spring-data-jpa将如何转换成另一个(DeadlineType)。您应该从存储库返回相同的类型,然后使用一些中间 util 类将其转换为模型类。

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

您可能已经可以使用它了,但是我使用下面的类创建了一个测试项目,允许您将数据检索到一个实体、投影或 dto 中。

Project-这将返回两次 code 列,一次命名为 code,另一次命名为 text (仅例如)。如上所述,您不需要@Projecting 注释

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 < ABDeadlineType,Long > ,但 Id 是 String,因此在下面更新为 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();


}

示例 Controller -直接访问存储库以简化代码

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

希望能帮上忙

莱斯

原来,当 表名与模型名不同时,你必须将注释更改为:

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

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

奇怪的是,它试图转换的类并不存在。这招对我很管用。

简单的解决方法:

在查询中使用{ 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 注释的查询) :

对于基于类的投影(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

我还有另外一个答案,我使用了投影和类的接口 我正在使用 ModelMapper 将我的投影映射到 Dto 类 因此,我的1Dto 类可能有许多投影,可以映射到 Dto 和用于味道

格莱德 实现‘ org.modmapper: model mapper: 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();
}

我的首要任务是

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

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

将内部的类名更改为 DeadlineType

扩展 JpaRepository < class,type >

例如:

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

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

当您希望获得 DeadlineType数据时,应该将查询保存在这样的存储库中,如

public interface DeadlineTypeRepository extends JpaRepository<DeadlineType, Long>

因此,要么替换 JpaRepository < > 中的类名 或者将查询放在另一个存储库中。那么您就不需要为它做任何映射或编写额外的代码。

对我来说,成功了。