2015-04-02 17 views
8

考慮下面的實體:如何配置傑克遜解串器嵌套的entites與Spring引導

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/" 
} 

做了一些調試,我發現傑克遜試圖從發佈對象的「regiao」屬性創建一個URI,等待一個字符串像「/ {id}」這樣的模板。我使用谷歌搜索,但無法找到適當的答案。

我在StackOverflow上看到了一些相關的問題,但都沒有爲我工作。

你們可以說這是什麼事嗎?

我認爲這只是一個配置,但不知道如何或在哪裏。

我也試圖避免自定義序列化器和反序列化器。

編輯:

如果我發佈與嵌套實體的唯一id的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" 
} 

正如我看到發送嵌套實體的正確方式就像「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

您可以發佈getter和setter方法的初步認識領域,在'Cidadae'即'regiao'和Regiao的屬性' '你想發佈? – 2015-04-03 09:11:11

+0

@ci_實體已更新。現在你可以看到完整的課程。 – 2015-04-06 13:27:27

+0

如何設置版本和ID字段?他們沒有構造函數或設置器。嘗試爲所有現場成員添加setter。有幾種方法可以讓它在沒有的情況下工作,但看看是否先添加setter。 – 2015-04-06 13:43:29

回答

3

我在EstadoRepository和RegiaoRepository類中使用@RestResource(exported = false)註解解決它。

它「隱藏」從德時,它的自動配置端點和東西春回購...

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

這對於這個問題並不適用。這與如何在Spring Boot上更改Jackson的ConditionalGenericConverter有關。我正在閱讀,看一些代碼,但沒有結果:( – 2015-05-27 17:51:01