Spring Data REST 自定义资源 URI 适用于 String 但不适用于 Long
Posted
技术标签:
【中文标题】Spring Data REST 自定义资源 URI 适用于 String 但不适用于 Long【英文标题】:Spring Data REST Custom Resource URI works for String but not Long 【发布时间】:2017-12-28 09:29:27 【问题描述】:我有一个模型:
public class MyModel
@Id private Long id;
private Long externalId;
// Getters, setters
我想使用externalId
作为我的资源标识符:
@Configuration
static class RepositoryEntityLookupConfig extends RepositoryRestConfigurerAdapter
@Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration configuration)
configuration
.withEntityLookup()
.forRepository(MyRepository.class, MyModel::getExternalId, MyRepository::findByExternalId);
如果externalId
是String
,这可以正常工作。但既然是数字 (Long
)
public interface MyRepository extends JpaRepository<MyModel, Long>
Optional<MyModel> findByExternalId(@Param("externalId") Long externalId);
调用时:/myModels/1
我得到:
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Long
at org.springframework.data.rest.core.config.EntityLookupConfiguration$RepositoriesEntityLookup.lookupEntity(EntityLookupConfiguration.java:213) ~[spring-data-rest-core-2.6.4.RELEASE.jar:na]
at org.springframework.data.rest.core.support.UnwrappingRepositoryInvokerFactory$UnwrappingRepositoryInvoker.invokeFindOne(UnwrappingRepositoryInvokerFactory.java:130) ~[spring-data-rest-core-2.6.4.RELEASE.jar:na]
at org.springframework.data.rest.webmvc.RepositoryEntityController.getItemResource(RepositoryEntityController.java:524) ~[spring-data-rest-webmvc-2.6.4.RELEASE.jar:na]
at org.springframework.data.rest.webmvc.RepositoryEntityController.getItemResource(RepositoryEntityController.java:335) ~[spring-data-rest-webmvc-2.6.4.RELEASE.jar:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_111]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_111]
...
一个单独的自定义 EntityLookupSupport<MyModel>
组件类有效。
我是否遗漏了一些东西来让它为Long
使用我的RepositoryRestConfigurerAdapter
中的方法引用?
【问题讨论】:
底层数据库列的类型是什么?该列是字符串吗? @Ben 数据库列类型:int,数据库:mysql。如果类型是 String,它可以工作(不需要转换器,模型字段将是 String 而不是 Long)。我需要它来处理 int 类型(外键约束)。 如果您调用/myModels/1L
而不是 /myModels/1
怎么办?可能是序列化问题
【参考方案1】:
尝试将此添加到您的 RepositoryEntityLookupConfig
课程中:
@Override
public void configureConversionService(ConfigurableConversionService conversionService)
conversionService.addConverter(String.class, Long.class, Long::parseLong);
super.configureConversionService(conversionService);
【讨论】:
已添加。我仍然得到“java.lang.ClassCastException:java.lang.String 无法转换为 java.lang.Long”。【参考方案2】:你真的需要自己设置配置吗?您可以尝试通过添加 @RepositoryRestResource 注释来使用 spring-boot 自动配置
@RepositoryRestResource(collectionResourceRel = "myModels", path = "myModels")
public interface MyRepository extends JpaRepository<MyModel, Long>
Optional<MyModel> findByExternalId(@Param("externalId") Long externalId);
在你的模型类中添加@Entity
@Entity
public class MyModel
@Id
private Long id;
@Column(name = "EXTERNAL_ID")
// Column annotation is not required if you respect case-sensitive
private Long externalId;
// Getters, setters
【讨论】:
对我不起作用。在 MyRepository 上添加@RepositoryRestResource
(同时删除配置)会产生与默认 findById
相同的效果。模型已经用 @Entity 注释并且列不需要注释(findByExternalId 否则有效)。【参考方案3】:
显然,默认的BackendIdConverter
(参见DefaultIdConverter
)对 ID 转换没有任何作用,另一方面 Spring Data Rest 不能使用存储库 ID 类型。因此,您必须自己转换或配置自定义 ID 转换器 bean,例如:
@Bean
public BackendIdConverter myModelBackendIdConverter()
return new BackendIdConverter()
@Override
public Serializable fromRequestId(final String id, final Class<?> entityType)
return Optional.ofNullable(id).map(Long::parseLong).orElse(null);
@Override
public boolean supports(final Class<?> delimiter)
return MyModel.class.isAssignableFrom(delimiter);
@Override
public String toRequestId(final Serializable id, final Class<?> entityType)
return Optional.ofNullable(id).map(Object::toString).orElse(null);
;
另见:
BackendIdHandlerMethodArgumentResolver
@BackendId
【讨论】:
【参考方案4】:您尝试调用的方法的签名似乎是:
forRepository(Class<R> type, Converter<T,ID> identifierMapping,
EntityLookupRegistrar.LookupRegistrar.Lookup<R,ID> lookup)
我看不出MyModel::getExternalId
是如何进行必要的转换的。
我会尝试以下方法:
@Configuration
static class RepositoryEntityLookupConfig extends RepositoryRestConfigurerAdapter
@Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration configuration)
configuration
.withEntityLookup()
.forRepository(MyRepository.class, Long::parseLong, MyRepository::findByExternalId);
【讨论】:
以上是关于Spring Data REST 自定义资源 URI 适用于 String 但不适用于 Long的主要内容,如果未能解决你的问题,请参考以下文章
Spring Data Rest:自定义 JsonDeserializer 中的 @Autowire
我可以让自定义控制器镜像 Spring-Data-Rest / Spring-Hateoas 生成的类的格式吗?