2015-04-02 6 views
8

Рассмотрят следующие объекты:Как настроить Джексон десериализатор для вложенных entites с весной Ботинками

package br.com.investors.domain.endereco; 

import com.google.common.base.Objects; 
import com.google.common.base.Strings; 
import com.google.common.collect.ComparisonChain; 
import org.hibernate.validator.constraints.NotBlank; 

import javax.persistence.*; 
import java.io.Serializable; 

import static com.google.common.base.Preconditions.checkArgument; 
import static javax.persistence.GenerationType.SEQUENCE; 

@Entity 
public class Regiao implements Serializable, Comparable<Regiao> { 

    @Id 
    @GeneratedValue(strategy = SEQUENCE) 
    private Long id; 

    @Version 
    private Long version; 

    @NotBlank 
    @Column(length = 100, unique = true) 
    private String nome = ""; 

    Regiao() {} 

    public Regiao(String nome) { 
     checkArgument(!Strings.isNullOrEmpty(nome), "Nome não pode ser vazio"); 
     this.nome = nome; 
    } 

    @Override 
    public boolean equals(Object obj) { 
     if (obj instanceof Regiao) { 
      Regiao o = (Regiao) obj; 
      return Objects.equal(this.nome, o.nome); 
     } 
     return false; 
    } 

    @Override 
    public int hashCode() { 
     return Objects.hashCode(nome); 
    } 

    @Override 
    public int compareTo(Regiao o) { 
     return ComparisonChain.start() 
       .compare(this.nome, o.nome) 
       .result(); 
    } 

    @Override 
    public String toString() { 
     return Objects.toStringHelper(getClass()).add("nome", nome).toString(); 
    } 

    public Long getId() { 
     return id; 
    } 

    public Long getVersion() { 
     return version; 
    } 

    public String getNome() { 
     return nome; 
    } 
} 

и

package br.com.investors.domain.endereco; 

import com.google.common.base.Objects; 
import com.google.common.base.Strings; 
import com.google.common.collect.ComparisonChain; 
import org.hibernate.validator.constraints.NotBlank; 

import javax.persistence.*; 
import javax.validation.constraints.NotNull; 
import java.io.Serializable; 

import static com.google.common.base.Preconditions.checkArgument; 
import static com.google.common.base.Preconditions.checkNotNull; 
import static javax.persistence.GenerationType.SEQUENCE; 

@Entity 
public class Cidade implements Serializable, Comparable<Cidade> { 

    @Id 
    @GeneratedValue(strategy = SEQUENCE) 
    private Long id; 

    @Version 
    private Long version; 

    @NotBlank 
    @Column(length = 100, unique = true) 
    private String nome = ""; 

    @NotNull 
    @ManyToOne 
    private Regiao regiao; 

    @NotNull 
    @ManyToOne 
    private Estado estado; 

    Cidade() {} 

    public Cidade(String nome, Regiao regiao, Estado estado) { 
     checkArgument(!Strings.isNullOrEmpty(nome), "Nome não pode ser vazio"); 
     checkNotNull(regiao, "Região não pode ser nulo"); 
     checkNotNull(estado, "Estado não pode ser nulo"); 

     this.nome = nome; 
     this.regiao = regiao; 
     this.estado = estado; 
    } 

    @Override 
    public boolean equals(Object obj) { 
     if (obj instanceof Cidade) { 
      Cidade o = (Cidade) obj; 
      return Objects.equal(this.nome, o.nome) && 
        Objects.equal(this.estado, o.estado) && 
        Objects.equal(this.regiao, o.regiao); 
     } 
     return false; 
    } 

    @Override 
    public int hashCode() { 
     return Objects.hashCode(nome, regiao, estado); 
    } 

    @Override 
    public int compareTo(Cidade o) { 
     return ComparisonChain.start() 
       .compare(this.estado, o.estado) 
       .compare(this.regiao, o.regiao) 
       .compare(this.nome, o.nome) 
       .result(); 
    } 

    @Override 
    public String toString() { 
     return Objects.toStringHelper(getClass()).add("nome", nome).add("regiao", regiao).add("estado", estado).toString(); 
    } 

    public Long getId() { 
     return id; 
    } 

    public Long getVersion() { 
     return version; 
    } 

    public String getNome() { 
     return nome; 
    } 

    public Regiao getRegiao() { 
     return regiao; 
    } 

    public Estado getEstado() { 
     return estado; 
    } 
} 

Я выкладываю в JSON к RestController

@RequestMapping(value = "/cidades", method = POST, consumes = APPLICATION_JSON_VALUE) 
void inserir(@RequestBody Cidade cidade) { 
    repository.save(cidade); 
} 

Я использую конфигурации по умолчанию Spring Boot для сериализации и десериализации объектов.

Если я отправляю JSON, как это, она отлично работает:

{ 
    "nome": "Cidade", 
    "regiao": "/10" 
} 

Но мне нужно отправить JSON как это:

{ 
    "nome": "Cidade", 
    "regiao": { 
     "id": 10, 
     "version": 0, 
     "nome": "regiao" 
    } 
} 

Если я так, я получаю ошибку

{ 
    "timestamp": "2015-04-02", 
    "status": 400, 
    "error": "Bad Request", 
    "exception": "org.springframework.http.converter.HttpMessageNotReadableException", 
    "message": "Could not read JSON: Template must not be null or empty! (through reference chain: br.com.investors.domain.endereco.Cidade[\"regiao\"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Template must not be null or empty! (through reference chain: br.com.investors.domain.endereco.Cidade[\"regiao\"])", 
    "path": "/cidades/" 
} 

Выполнение некоторой отладки, я обнаружил, что Джексон пытается создать URI из свойства «regiao» отправленного объекта, ожидая строки шаблон типа "/ {id}". Я ищу его, но не могу найти правильный ответ.

Я видел некоторые связанные с этим проблемы в StackOverflow, но никто не работал для меня.

Можете ли вы, ребята, сказать, в чем дело?

Я думаю, что это всего лишь конфигурация, но не знаю, как и где.

Я также стараюсь избегать специальных сериализаторов и десериализаторов.

EDIT:

Если я отправляю JSON только с идентификаторами вложенных сущностей, как это:

{ 
    "nome": "Cidade", 
    "estado": "10", 
    "regiao": "10" 
} 

Я получаю сообщение:

{ 
    "timestamp": "2015-04-07", 
    "status": 400, 
    "error": "Bad Request", 
    "exception": "org.springframework.http.converter.HttpMessageNotReadableException", 
    "message": "Could not read JSON: Failed to convert from type java.net.URI to type br.com.investors.domain.endereco.Estado for value '10'; nested exception is java.lang.IllegalArgumentException: Cannot resolve URI 10. Is it local or remote? Only local URIs are resolvable. (through reference chain: br.com.investors.domain.endereco.Cidade[\"estado\"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Failed to convert from type java.net.URI to type br.com.investors.domain.endereco.Estado for value '10'; nested exception is java.lang.IllegalArgumentException: Cannot resolve URI 10. Is it local or remote? Only local URIs are resolvable. (through reference chain: br.com.investors.domain.endereco.Cidade[\"estado\"])", 
    "path": "/cidades" 
} 

В I что правильный способ отправки вложенного объекта похож на «regiao»: «/ 10», я жестко кодирую это в своем Javascript для обхода:

function(item) { 
    item.regiao = "/" + item.regiao.id; //OMG 
    item.estado = "/" + item.estado.id; //OMG!! 

    if (item.id) { 
     return $http.put('/cidades/' + item.id, item); 
    } else { 
     return $http.post('/cidades', item); 
    } 
} 

Это работает, но это отстой. Как я могу исправить это в Javascript или настроить Джексона?

Чтение некоторых документов, что-то связано с UriToEntityConverter, но до сих пор не знает правильного способа настройки этого.

Спасибо.

+0

Вы можете разместить поглотитель и сеттеры для relavant полей, то есть '' regiao' в Cidadae' и атрибуты 'Regiao 'вы пытаетесь опубликовать? –

+0

Обновлено @ci_ объектов. Теперь вы можете увидеть полные классы. –

+0

Как вы устанавливаете поля версии и id? Для них нет конструкторов или сеттеров. Попробуйте добавить сеттеры для всех ваших участников. Есть способы, чтобы он работал без него, но посмотрите, работает ли сначала сеттеры. –

ответ

3

Я решил его с помощью @RestResource (exported = false) аннотации классов EstadoRepository и RegiaoRepository.

Он «скрывает» от репо с весны, когда это автонастройки конечные точки и прочее ...

0

Вы можете использовать аннотацию @JsonIgnoreProperties (ignoreUnknown = true) в своем классе сущности, подобном этому.

@Entity 
@JsonIgnoreProperties(ignoreUnknown = true) 
public class Area implements Serializable, CompanyAware, IdentifiableModel<Long> { 
private static long serialVersionUID = 1L; 

@Id 
@GeneratedValue(strategy = GenerationType.AUTO) 
private Long id = 0l; 
@NotNull 
@NotEmpty 
@Column(nullable = false, unique = true) 
private String name; 
@NotNull 
@ManyToOne(fetch = FetchType.EAGER) 
@JoinColumn(nullable = false) 
private Region region; 
private boolean active = true; 

@ManyToOne 
@JoinColumn(updatable = false) 
private Company company; 

public Long getId() { 
    return id; 
} 

public void setId(Long id) { 
    this.id = id; 
} 

@Override 
public int hashCode() { 
    int hash = 0; 
    hash += (getId() != null ? getId().hashCode() : 0); 
    return hash; 
} 

@Override 
public boolean equals(Object object) { 
    // TODO: Warning - this method won't work in the case the id fields are not set 
    if (!(object instanceof Area)) { 
     return false; 
    } 
    Area other = (Area) object; 
    if ((this.getId() == null && other.getId() != null) || (this.getId() != null && !this.id.equals(other.id))) { 
     return false; 
    } 
    return true; 
} 

@Override 
public String toString() { 
    return "Area[ id=" + getId() + " ]"; 
} 

/** 
* @return the name 
*/ 
public String getName() { 
    return name; 
} 

/** 
* @param name the name to set 
*/ 
public void setName(String name) { 
    this.name = name; 
} 

/** 
* @return the region 
*/ 
public Region getRegion() { 
    return region; 
} 

/** 
* @param region the region to set 
*/ 
public void setRegion(Region region) { 
    this.region = region; 
} 

/** 
* @return the active 
*/ 
public boolean isActive() { 
    return active; 
} 

/** 
* @param active the active to set 
*/ 
public void setActive(boolean active) { 
    this.active = active; 
} 

/** 
* @return the company 
*/ 
public Company getCompany() { 
    return company; 
} 

/** 
* @param company the company to set 
*/ 
public void setCompany(Company company) { 
    this.company = company; 
} 
} 

Это может решить вашу проблему. Он будет игнорировать неизвестные отсутствующие поля в объекте json. Он будет использовать только доступные поля в объекте json и игнорировать неизвестные поля.

+0

Это не работает для проблемы. Это как-то связано с тем, как изменить Jackson's ConditionalGenericConverter на Spring Boot. Я читаю об этом, смотрю некоторые коды, но пока нет результата :( –

Смежные вопросы