【问题标题】:Spring Data REST Custom Resource URI works for String but not LongSpring Data REST 自定义资源 URI 适用于 String 但不适用于 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);
    }
}

如果externalIdString,这可以正常工作。但既然是数字 (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&lt;MyModel&gt; 组件类有效。

我是否遗漏了一些东西来让它为Long 使用我的RepositoryRestConfigurerAdapter 中的方法引用?

【问题讨论】:

  • 底层数据库列的类型是什么?该列是字符串吗?
  • @Ben 数据库列类型:int,数据库:MySQL。如果类型是 String,它可以工作(不需要转换器,模型字段将是 String 而不是 Long)。我需要它来处理 int 类型(外键约束)。
  • 如果您调用 /myModels/1L 而不是 /myModels/1 怎么办?可能是序列化问题

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


【解决方案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);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2017-09-27
      • 2015-09-24
      • 1970-01-01
      • 1970-01-01
      • 2018-12-10
      • 1970-01-01
      • 1970-01-01
      • 2011-02-07
      • 1970-01-01
      相关资源
      最近更新 更多