Spring Data Rest字段转换器

3

我在使用自定义转换器时遇到了麻烦,这是在spring data REST项目中(无控制器应用程序和严格的Java配置)。

我有两个实体,一个是员工(Employee),另一个是州(State),它们之间的关系是@ManyToOne,相信我们都知道。然而,问题在于将state字段(字段名为state)从String转换为State对象,并将其setState()Employee类中以便持久化到数据库中。

package com.hr.domain;

@Entity
public class Employee implements Serializable {

   private static final long serialVersionUID = 1L;

   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "state_id", nullable = true)
   private Long id;
   private String firstname;
   private State state;

   @StateConverter
   @ManyToOne(fetch = FetchType.LAZY)
   @JoinColumn(name = "employee_state_id_fk", nullable = false, insertable = true, updatable = true)
   private State state;

   //GETTERS AND SETTERS
   public String getFirstname() {
      return firstname();
   }

   public void setFirstname(String firstname) {
      this.firstname = firstname;
   }

   public String getState() {
    return state();
   }

   public void setState(State state) {
     this.state = state;
   }

   //HASHCODES AND EQUALS

}


package com.hr.domain;

@Entity
public class State implements Serializable {

   private static final long serialVersionUID = 1L;

   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "state_id", nullable = true)
   private Long id;
   private String state_name;

   //GETTERS AND SETTERS

  //TO STRING
  @Override
  public String toString() {
    return "State [id=" + id + ", state_name=" + state_name + "]";
  }       

}

我已经将转换器注册到转换服务中,但仍然无法在表单提交时将字符串转换为状态对象。

@Bean//(name="conversionService")
public ConversionService getConversionService() {       
    ConversionServiceFactoryBean bean = new ConversionServiceFactoryBean();
    bean.setConverters(getConverters());
    bean.afterPropertiesSet();
    ConversionService object = bean.getObject();
    System.out.println(object);
    return object;
}

private Set<Converter> getConverters() {    
    Set<Converter> converters = new HashSet<Converter>();
    converters.add(new StringToStateTypeConverter());
    return converters;      
}

这是我的状态转换器(StateConverter)。
@Component
@StateConverter
public class StringToStateTypeConverter implements Converter<String, State> {

    @Autowired
    StateRepository repository;

    public State convert(String source) {
        return repository.findOne(new Long(source));
    }

}

提交时,我收到了以下错误:

Caused by: org.springframework.core.convert.ConversionFailedException: 无法将值“AB”从类型java.net.URI转换为类型com.hr.domain.State;

感谢任何形式的帮助。

愿原力与你同在。 敬礼。

以下是错误追踪信息

17:21:29,975 ERROR [org.springframework.data.rest.webmvc.AbstractRepositoryRestController] (default task-13) Could not read JSON: Failed to convert from type java.net.URI to type com.hr.domain.State for value 'AB'; nested exception is java.lang.IllegalArgumentException: Cannot resolve URI AB. Is it local or remote? Only local URIs are resolvable. (through reference chain: com.hr.domain.Employee["State"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Failed to convert from type java.net.URI to type com.hr.domain.State for value 'AB'; nested exception is java.lang.IllegalArgumentException: Cannot resolve URI AB. Is it local or remote? Only local URIs are resolvable. (through reference chain: com.hr.domain.Employee["State"]): org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Failed to convert from type java.net.URI to type com.hr.domain.State for value 'AB'; nested exception is java.lang.IllegalArgumentException: Cannot resolve URI AB. Is it local or remote? Only local URIs are resolvable. (through reference chain: com.hr.domain.Employee["State"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Failed to convert from type java.net.URI to type com.hr.domain.State for value 'AB'; nested exception is java.lang.IllegalArgumentException: Cannot resolve URI AB. Is it local or remote? Only local URIs are resolvable. (through reference chain: com.hr.domain.Employee["State"])
    at org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.readJavaType(MappingJackson2HttpMessageConverter.java:228) [spring-web-4.0.5.RELEASE.jar:4.0.5.RELEASE]

...........
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Failed to convert from type java.net.URI to type com.hr.domain.State for value 'AB'; nested exception is java.lang.IllegalArgumentException: Cannot resolve URI AB. Is it local or remote? Only local URIs are resolvable. (through reference chain: com.hr.domain.Employee["State"])
    at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:232) [jackson-databind-2.3.3.jar:2.3.3]
    at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:197) [jackson-databind-2.3.3.jar:2.3.3]

Caused by: org.springframework.core.convert.ConversionFailedException: Failed to convert from type java.net.URI to type com.hr.domain.State for value 'AB'; nested exception is java.lang.IllegalArgumentException: Cannot resolve URI AB. Is it local or remote? Only local URIs are resolvable.
    at org.springframework.data.rest.core.UriToEntityConverter.convert(UriToEntityConverter.java:106) [spring-data-rest-core-2.1.0.RELEASE.jar:]
    at org.springframework.data.rest.webmvc.json.PersistentEntityJackson2Module$UriStringDeserializer.deserialize(PersistentEntityJackson2Module.java:359) [spring-data-rest-webmvc-2.1.0.RELEASE.jar:]

Caused by: java.lang.IllegalArgumentException: Cannot resolve URI AB. Is it local or remote? Only local URIs are resolvable.
    ... 94 more

你应该发布完整的堆栈跟踪。 - Serge Ballesta
1
引起错误的查询是什么,什么是 AB - Serge Ballesta
据我所知,spring-data-rest使用JSON作为输入和输出的格式。您是否尝试过其他方式? - Serge Ballesta
哎呀,spring-data-rest 中有很多神奇的东西,你正在尝试做一些它没有预料到的事情。我建议的修改有没有破坏什么?如果没有,我可能有一个想法... - Serge Ballesta
我创建了那个转换器进行测试,但似乎没有被调用。之后我在我的状态存储库中创建了一个 findByState__name() 方法。然而,在我的 HTTP POST 请求期间,转换器仍未被调用。 - OchiengOlanga
显示剩余4条评论
1个回答

1
您正在注册一个新的 ConversionService 。它将替换Spring默认注册的具有许多通常假定存在的转换器的默认服务。而且,您创建了一个新的转换器,而不是使用已配置的bean。相反,您应该:
  • 注册spring的默认转换服务及其所有默认转换器
  • 将您的转换器添加到其中

您的转换服务初始化可能如下所示:

private @Autowired StringToStateTypeConverter stringToStateTypeConverter;

@Bean//(name="conversionService")
public ConversionService getConversionService() {       
    ConversionServiceFactoryBean bean = new DefaultFormattingConversionService();
    bean.addConverter(String.class, State.class, stringToStateTypeConverter);
    return bean;
}

编辑

由于错误来自于从URI转换为State的问题,您可以尝试添加一个从URIState的转换器(假设您的存储库有一个方法findByName通过其name查找State

@Component
@StateConverter
public class URIToStateTypeConverter implements Converter<URI, State> {
    @Autowired
    StateRepository repository;

    public State convert(URI uri) {
        String source = uri.toString();
        try {
            long id = Long.valueOf(source);
            return repository.findOne(id);
        } catch (NumberFormatException e) { // should be a name ??
            return repository.findByName(source);
        }
    }
}

转换服务的初始化将变为:

private @Autowired StringToStateTypeConverter stringToStateTypeConverter;
private @Autowired URIToStateTypeConverter uriToStateTypeConverter;

@Bean//(name="conversionService")
public ConversionService getConversionService() {       
    ConversionServiceFactoryBean bean = new DefaultFormattingConversionService();
    bean.addConverter(String.class, State.class, stringToStateTypeConverter);
    bean.addConverter(URI.class, State.class, uriToStateTypeConverter);
    return bean;
}

但我不确定它是否会被spring-data-rest使用


谢谢Serge的建议。我按照你的建议更改了我的自定义转换器的注册。是否有一种方法可以在每次表单提交时调用转换器(使用注释等),因为我仍然遇到了问题,就像问题描述中所述的那样。请注意:我尽可能地想避免使用控制器。 - OchiengOlanga

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接