【问题标题】:Spring Data REST + Hibernate 5 + Jackson LAZY serialization failSpring Data REST + Hibernate 5 + Jackson LAZY 序列化失败
【发布时间】:2018-04-17 05:12:22
【问题描述】:

我有 2 个实体:用户和地址。 关系设置如下:

地址

@Entity
@Table(name = "addresses")
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Address {
    private static final long serialVersionUID = 1L;
    @Id
    @JsonIgnore
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "username")
    private User user;

用户

@Entity
@Table(name = "users")
public class User {
    @Id
    private String username;

    (...)

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
    private List<Address> addresses;

每当我为具有一个或多个地址实体的用户的用户名调用 GET http://localhost:8080/api/data/users/{USERNAME}/addresses 时,结果是:

状态 500

{
    "cause": null,
    "message": "Id must be assignable to Serializable!: to.wysylam.couriersystem.api.entities.User"
}

另外值得一提的是,即使 Spring Data REST 生成链接:

"_links": {
  "self": {
    "href": "http://localhost:8080/api/data/addresses/33"
  },
  "address": {
    "href": "http://localhost:8080/api/data/addresses/33"
  },
  "user": [
    {
      "href": "http://localhost:8080/api/data/users"
    },
    {
      "href": "http://localhost:8080/api/data/addresses/33/user"
    }
  ]
}

http://localhost:8080/api/data/addresses/33/user 链接根本不起作用。 (抛出 java.lang.NoClassDefFoundError: javax/servlet/jsp/jstl/core/Config)

到目前为止,我尝试在 Address 实体中将 LAZY 更改为 EAGER FetchingType,然后行为发生如下变化:

  • 我不能GET http://localhost:8080/api/data/addresses(错误消息为 500,“Id 必须可分配给 Serializable!:to.wysylam.couriersystem.api.entities.User”)

  • 我可以GET http://localhost:8080/api/data/users/{USERNAME}/addresses

老实说,我现在没有想法。

配置文件定义如下:

@Configuration
@ComponentScan(basePackages = { "to.wysylam.couriersystem.api.controllers",
                            "to.wysylam.couriersystem.api.services",
                            "to.wysylam.couriersystem.api.hateoas"
                            })
@Import({JpaConfig.class,
    SecurityConfig.class,
    DataRestConfig.class,
    RepositoryRestMvcConfiguration.class
})
public class AppConfig {

}

@Configuration
public class DataRestConfig extends RepositoryRestConfigurerAdapter {
    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config){
    config.setRepositoryDetectionStrategy(
                 RepositoryDetectionStrategy.RepositoryDetectionStrategies.ANNOTATED
    );
    config.exposeIdsFor(User.class);
    config.setBasePath("/data");
}

@Bean
protected Module module(){
    return new Hibernate5Module();
}

@Override
public void configureConversionService(ConfigurableConversionService configurableConversionService){
    configurableConversionService.addConverter(String.class, String[].class, stringToStringArrayConverter());
}

private Converter<String, String[]> stringToStringArrayConverter(){
    return (source) -> StringUtils.delimitedListToStringArray(source, ";");

}
}

@Configuration
@EnableJpaRepositories(basePackages =   "to.wysylam.couriersystem.api.repositories")
public class JpaConfig {
private static Properties getJpaProperties(){
    Properties jpaProperties = new Properties();
    jpaProperties.put("hibernate.hbm2ddl.auto", "validate");
    jpaProperties.put("hibernate.default_schema", "couriersystem");
    jpaProperties.put("hibernate.dialect",  "org.hibernate.dialect.PostgreSQL82Dialect");
    jpaProperties.put("hibernate.enable_lazy_load_no_trans","true");
    return jpaProperties;
}

@Bean
public static LocalContainerEntityManagerFactoryBean entityManagerFactory(){
    LocalContainerEntityManagerFactoryBean asBean = new LocalContainerEntityManagerFactoryBean();
    asBean.setDataSource(dataSource());
    asBean.setPackagesToScan("to.wysylam.couriersystem.api.entities");
    asBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
    asBean.setJpaProperties(getJpaProperties());

    return asBean;
}

@Bean(name = "dataSource")
public static DriverManagerDataSource dataSource(){
    DriverManagerDataSource bean = new DriverManagerDataSource();
    bean.setDriverClassName("org.postgresql.Driver");
    bean.setUrl("jdbc:postgresql://localhost:5432/postgres");
    bean.setUsername("dev");
    bean.setPassword("pwd");
    return bean;
}

@Bean
public static JpaTransactionManager transactionManager(){
    JpaTransactionManager asBean = new JpaTransactionManager();
    asBean.setEntityManagerFactory(entityManagerFactory().getObject());
    return asBean;
}

@Bean
public static PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor(){
    return new PersistenceExceptionTranslationPostProcessor();
}

@Bean
public static HibernateExceptionTranslator hibernateExceptionTranslator(){
    return new HibernateExceptionTranslator();
}
}

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "to.wysylam.couriersystem.api.controllers")
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Import(AppConfig.class)
public class WebConfig implements WebMvcConfigurer {

@Bean
public InternalResourceViewResolver viewResolver(){
    InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
    viewResolver.setViewClass(JstlView.class);
    viewResolver.setPrefix("/WEB-INF/pages/");
    viewResolver.setSuffix(".jsp");

    return viewResolver;
}

@Override
public void addFormatters(FormatterRegistry registry){
    registry.removeConvertible(String.class, String[].class);
    registry.addConverter(String.class, String[].class, stringToStringArrayConverter());
}

private Converter<String, String[]> stringToStringArrayConverter(){
    return (source) -> StringUtils.delimitedListToStringArray(source, ";");
}
}

任何帮助表示赞赏

更新

在此期间,我尝试将 User 类的 ID 从 String 更改为 Long。 但是,问题仍然存在。显然...

更新 2

一些有趣的日志转储(在处理GET &lt;host&gt;/api/data/addresses时):

[DEBUG] 2017-11-06 18:25:01.053 [http-nio-8080-exec-39] ExceptionHandlerExceptionResolver - Resolving exception from handler [public org.springframework.hateoas.Resources<?> org.springframework.data.rest.webmvc.RepositoryEntityController.getCollectionResource(org.springframework.data.rest.webmvc.RootResourceInformation,org.springframework.data.rest.webmvc.support.DefaultedPageable,org.springframework.data.domain.Sort,org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler) throws org.springframework.data.rest.webmvc.ResourceNotFoundException,org.springframework.web.HttpRequestMethodNotSupportedException]: java.lang.IllegalArgumentException: Id must be assignable to Serializable!: to.wysylam.couriersystem.api.entities.User

[DEBUG] 2017-11-06 18:25:01.055 [http-nio-8080-exec-39] ExceptionHandlerExceptionResolver - Resolving exception from handler [public org.springframework.hateoas.Resources<?> org.springframework.data.rest.webmvc.RepositoryEntityController.getCollectionResource(org.springframework.data.rest.webmvc.RootResourceInformation,org.springframework.data.rest.webmvc.support.DefaultedPageable,org.springframework.data.domain.Sort,org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler) throws org.springframework.data.rest.webmvc.ResourceNotFoundException,org.springframework.web.HttpRequestMethodNotSupportedException]: java.lang.IllegalArgumentException: Id must be assignable to Serializable!: to.wysylam.couriersystem.api.entities.User

【问题讨论】:

    标签: java spring hibernate jackson spring-data-rest


    【解决方案1】:

    在多对一课程中设置 @JsonSerialize(as = Address.class) 对我的情况有所帮助...

    【讨论】:

    • 不幸的是,它对我不起作用......但是我还能在这里做错什么吗?
    【解决方案2】:

    当然,我的代码有错误。

    我定义了一个ResourceProcessor&lt;Resource&lt;Address&gt;&gt; 并且它认为用户属性是理所当然的,而在我的数据库中有一些地址行没有在关系中定义用户。

    简单的空检查解决了它,当然。

    结案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-21
      • 2020-06-08
      • 2016-01-11
      • 2016-11-15
      • 1970-01-01
      • 2017-07-04
      • 1970-01-01
      • 2018-11-07
      相关资源
      最近更新 更多