2012-09-28 56 views
0

我們使用Jersey/Jackson作爲我們的REST應用程序。傳入的JSON字符串被傑克遜映射到後端的@Entity對象以被持久化。Jackson對象映射 - 將傳入的JSON字段映射到基類中的受保護屬性

問題來自我們用於所有實體的基類。它有一個受保護的id屬性,我們希望通過REST交換,因此當我們發送一個具有依賴關係的對象時,hibernate將自動通過它們的id獲取這些依賴關係。

Howevery,Jackson不會訪問setter,即使我們在子類中重寫它以公開。我們也嘗試使用@JsonSetter,但無濟於事。也許傑克遜只是着眼於基礎類,並認爲ID不是訪問,所以它跳過設置它...

@MappedSuperclass 
public abstract class AbstractPersistable<PK extends Serializable> implements Persistable<PK> { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private PK id; 

    public PK getId() { 
     return id; 
    } 

    protected void setId(final PK id) { 
     this.id = id; 
    } 

子類:

public class A extends AbstractPersistable<Long> { 
    private String name; 
} 

public class B extends AbstractPersistable<Long> { 
    private A a; 

    private int value; 

    // getter, setter 

    // make base class setter accessible 
    @Override 
    @JsonSetter("id") 
    public void setId(Long id) { 
     super.setId(id); 
    } 
} 

現在如果有一些作爲我們的數據庫,我們希望通過REST資源來創建新B:

@POST 
@Consumes(MediaType.APPLICATION_JSON) 
@Produces(MediaType.APPLICATION_JSON) 
@Transactional 
public Response create(B b) { 
    if (b.getA().getId() == null) 
     cry(); 
} 

用JSON字符串這樣{"a":{"id":"1","name":"foo"},"value":"123"}

傳入的B將有A引用但沒有ID。


有沒有辦法告訴傑克遜要麼忽略基類的setter或告訴它使用的子類的setter呢?

我剛剛發現了約@JsonTypeInfo,但我不確定這是我需要什麼或如何使用它。

感謝您的幫助!


編輯

StaxMan有我擔心我在這裏失去了一些東西,所以我要添加servlet配置,因爲這是唯一的另外一點我能想到的任何地方可能出問題,如果我描述的行爲實際上應該是可以不添加XML註釋的setter(在我的答案中描述):

<servlet> 
    <servlet-name>jersey-serlvet</servlet-name> 
    <servlet-class> 
     com.sun.jersey.spi.spring.container.servlet.SpringServlet 
    </servlet-class> 
    <init-param> 
     <param-name>com.sun.jersey.config.property.packages</param-name> 
     <param-value>path.to.rest.resources</param-value> 
    </init-param> 
    <load-on-startup>1</load-on-startup> 
</servlet> 
<servlet-mapping> 
    <servlet-name>jersey-serlvet</servlet-name> 
    <url-pattern>/rest/*</url-pattern> 
</servlet-mapping> 
+0

我想你可能需要一個更設置啓用「POJO映射」,因爲它是不使用默認的一個? – StaxMan

回答

2

所以,找到了解決辦法已經:

必須在所有覆蓋ID制定者使用@XmlElement(name="id")

@XmlElement(name="id") 
public void setId(Long id) { 
    super.setId(id); 
} 
0

不,它應該工作原樣。 Jackson串行器查看實際的運行時類(包括所有基類屬性),並應該看到getter(「getId()」)。 所以其他事情正在發生。

基礎上的解決方案,我想知道,如果你使用的可能不是基於POJO傑克遜映射,但其他什麼東西......

+0

感謝您的回答!但getId不是問題。 SetId是。我試圖將傳入的ID保存到POJO中,其中setId是基類中的受保護方法,因此可以從子類外部訪問。所以真正唯一的方法是增加對子類的setId可見性。但由於某種原因,傑克遜並未接受這一點。 – Pete

+0

受保護的修飾符對於setters來說沒有問題:Jackson將使用Reflection,並且它可以很容易地檢測到非公開的setter(這是默認完成的 - 不像getter,只有'public'是自動檢測的),以及調用它。這就是爲什麼我對你的問題感到困惑。 – StaxMan

+0

現在我也很困惑。如果你說這應該起作用,爲什麼不呢?設置如所述。難道我無意中做了某種設定嗎?我將把我的servlet配置添加到問題中。除此之外,我不認爲我有任何影響傑克遜行爲的地方。 – Pete