在具有ConversionFailedException的PUT调用上,自定义实体查找失败

时间:2019-02-12 13:59:16

标签: spring spring-data spring-data-rest

我遇到的问题与this question非常相似,但不完全相同。我想使用基于字符串的外部ID,因此请像在the documentation中那样设置自定义EntityLookup

这对于GETPOSTDELETE来说非常有用,但是PUT失败,出现ConversionFailedException

我可以使用以下最小配置重现错误,以使用username作为要查找的字段:

User.java

@Entity
public class User {
    @Id
    private Long id;
    private String username;
    private String fullName;
}

UserRepo.java

@RepositoryRestResource(exported = true)
public interface UserRepo extends PagingAndSortingRepository<User, Long> {
    Optional<User> findByUsername(String username);
}

SpringDataRestCustomization.java

public class SpringDataRestCustomization implements RepositoryRestConfigurer {
    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        config.withEntityLookup()
        .forRepository(UserRepo.class, User::getUsername, UserRepo::findByUsername);
    }
}

然后我可以POST新建记录并通过GET /users/username来获取它们,但是对现有资源的PUT会出现以下错误:

o.s.d.r.w.RepositoryRestExceptionHandler : Failed to convert from type [java.lang.String] to type [java.lang.Long] for value 'username'; nested exception is java.lang.NumberFormatException: For input string: "username"

org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.lang.Long] for value 'username'; nested exception is java.lang.NumberFormatException: For input string: "username"
    at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:46) ~[spring-core-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:191) ~[spring-core-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:174) ~[spring-core-5.1.4.RELEASE.jar:5.1.4.RELEASE]
    at org.springframework.data.mapping.model.ConvertingPropertyAccessor.convertIfNecessary(ConvertingPropertyAccessor.java:123) ~[spring-data-commons-2.1.4.RELEASE.jar:2.1.4.RELEASE]
    at org.springframework.data.mapping.model.ConvertingPropertyAccessor.setProperty(ConvertingPropertyAccessor.java:61) ~[spring-data-commons-2.1.4.RELEASE.jar:2.1.4.RELEASE]
    at org.springframework.data.rest.webmvc.config.PersistentEntityResourceHandlerMethodArgumentResolver.lambda$resolveArgument$3(PersistentEntityResourceHandlerMethodArgumentResolver.java:149) ~[spring-data-rest-webmvc-3.1.4.RELEASE.jar:3.1.4.RELEASE]
    at java.base/java.util.Optional.ifPresent(Optional.java:183) ~[na:na]
    at org.springframework.data.rest.webmvc.config.PersistentEntityResourceHandlerMethodArgumentResolver.resolveArgument(PersistentEntityResourceHandlerMethodArgumentResolver.java:146) ~[spring-data-rest-webmvc-3.1.4.RELEASE.jar:3.1.4.RELEASE]
    at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:126) ~[spring-web-5.1.4.RELEASE.jar:5.1.4.RELEASE]

1 个答案:

答案 0 :(得分:0)

那绝对是一个错误。

发生这种情况是因为PUT repository/{id}端点也可以用于创建具有给定ID的新实体。 因此,在PUT请求期间,它将尝试将URL中的id放入对象的id属性中。但是-由于您具有唯一的EntityLookup-URL片段不是实体的ID属性...

看来作者只是忘了处理此案。而且,当我查找源代码时,我看不到任何简单的解决方法。

我认为PATCH请求仍然可以使用,因此,如果您可以避免使用PUT请求,那么这可能是一个解决方案。

我个人不喜欢整个EntityLookup功能。 (结果是:听起来不错,不起作用:))我认为URL的id片段应该是实体的实际ID。 也许它没有违反REST原则,但我仍然觉得不合适。

相反,如果您想通过用户名来获取用户,则可以随时使用users / search / findByUsername端点,然后,如果您想通过PUT请求修改对象,则在响应中将具有_self链接。以后。