2012-05-11 73 views
3

有沒有辦法配置@XmlTransient JPA2.0註釋,它只會在Java對象序列化爲xml時阻止JAXB機制,而不是傳入XML轉換爲java對象時阻止JAXB機制?@XmlTransient用於序列化但不用於反序列化?

背景:我有一個說XML的REST API。有一個端點可以創建一個新的Attachment對象。當我們提到附件時,這個類中有一個byte []字段。在進一步的附件列表中,我不想傳遞每個附件的byte []內容。

@Entity 
@XmlRootElement 
public class Attachment { 

private String name; 

private String mimeType; 

private byte[] dataPart; 

public String getName() { 
    return name; 
} 

public void setName(String name) { 
    this.name = name; 
} 

public String getMimeType() { 
    return mimeType; 
} 

public void setMimeType(String mimeType) { 
    this.mimeType = mimeType; 
} 

public byte[] getDataPart() { 

    return dataPart.clone(); 
} 

public void setDataPart(byte[] dataPart) { 
    this.dataPart = dataPart.clone(); 
} 
} 

所以,當我標記getDataPart()與XmlTransient,到來的字節[]的數據被忽略,並且設置爲空 - >它的丟失。 任何想法如何指定XmlTransient的方向?

回答

1

我必須自己回答這個問題=) 我通過使用自定義的XmlAdapter解決了這個問題,它只會在一個方向上轉換二進制數據。這仍然是一個黑客攻擊,我們不再使用它了。下面的原因。

這裏是適配器:

public class DuplexBase64MarshallAdapter extends XmlAdapter<String, byte[]> { 

     /** 
     * running the adapter in half duplex mode means, the incoming data is marshaled but the 
     * outgoing data not. 
     */ 
     public static final boolean HALF_DUPLEX = false; 

     /** 
     * Running the adapter in full duplex means, the incoming and outgoing data is marshalled. 
     */ 
     public static final boolean FULL_DUPLEX = true; 

     private boolean isFullDuplexMode; 

     public DuplexBase64MarshallAdapter() { 
      this.isFullDuplexMode = HALF_DUPLEX; 
     } 

     /** 
     * Constructor 
     * 
     * @param fullDuplex 
     *   use {@link #HALF_DUPLEX} or {@link #FULL_DUPLEX} 
     */ 
     public DuplexBase64MarshallAdapter(boolean fullDuplex) { 
      this.isFullDuplexMode = fullDuplex; 
     } 

     @Override 
     public byte[] unmarshal(String v) throws Exception { 
      return Base64.decode(v); 
     } 

     /** 
     * Return always an empty string. We do not want to deliver binary content here. 
     */ 
     @Override 
     public String marshal(byte[] v) throws Exception { 
      if(isFullDuplexMode) { 
       return Base64.encodeBytes(v); 
      } 
      return ""; 
     } 

    } 

的實體需要與此適配器進行註釋:

@Entity 
@XmlRootElement 
public class Attachment { 

    private String name; 

    private String mimeType; 

    private byte[] dataPart; 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public String getMimeType() { 
     return mimeType; 
    } 

    public void setMimeType(String mimeType) { 
     this.mimeType = mimeType; 
    } 

    @XmlJavaTypeAdapter(DuplexBase64MarshallAdapter.class) 
    public byte[] getDataPart() { 

     return dataPart.clone(); 
    } 

    public void setDataPart(byte[] dataPart) { 
     this.dataPart = dataPart.clone(); 
    } 
} 

此解決方案爲exepcted。但有一個缺點:其中一個意圖是在處理/加載附件數據時不要讓休眠加載二進制數據。但那不是它的工作原理。在這種情況下,二進制數據由休眠加載,因爲它發送到XMLAdapter,但沒有轉換爲base64 :(

+0

當然!太糟糕了@XmlTransient中沒有方向屬性。 –

0

我認爲你的問題不是關於「是,將其序列化,但不要反序列化」,而是:傳輸數據客戶端 - >服務器,而不是服務器 - >客戶端。你想讓你的服務器反序列化傳入的byte[]數據吧?你只是不想(總是)在返回實體時將其發送出去。

如果是這種情況,可以在發送實體之前將其設置爲空。在您的REST資源,做這樣的事情:

@PersistenceContext(unitName = "myPersistenceUnit") 
privat EntityManager em; 

@Path("/upload") 
@POST 
public Response storeAttachment(JAXBElement<Attachment> jaxbAttachment) { 
    Attachment attachment = jaxbAttachment.getValue(); 

    // store it in the DB 
    em.persist(attachment); 

    // detach it, so that modifications are no longer reflected in the database 
    em.detach(attachment); 

    // modify your guts out, it'll only affect this instance 
    attachment.setDataPart(null); // <-- NPE if you don't get rid of .clone() in your entity 

    URI newUri = ... 
    return Response.created(newUri).entity(attachment).build(); 
} 
+0

嗯,謝謝,但實體是一個更復雜的數據結構的一部分。所以如果有可能的附件作爲孩子,我無法檢查每種方法。 – martin

0

萬一你只想序列化的東西,但從來沒有反序列化,使用@XmlAccessorType(XmlAccessType.FIELD),只提供了一個@XmlElement註解的getter。

@XmlRootElement 
@XmlAccessorType(XmlAccessType.FIELD) 
public class Something { 

    public Integer foo; 

    public Integer getFoo() { 
    return foo; 
    } 

    public void setFoo(Integer foo) { 
    this.foo = foo; 
    } 

    @XmlElement 
    public Integer getBar() { 
    return 42; 
    } 
} 

(假設foo設置爲17),這將馬歇爾爲

<something> 
    <foo>17</foo> 
    <bar>42</bar> 
</something> 

如果反序列化(具有相同的類定義),bar將不會被解組設置(因爲它找不到一個setter)。

0

漢斯,我有同樣的問題。您的答案讓我以正確的方式。 如果問題僅僅是序列化,這樣做的伎倆:

,然後使用這種方式:

@XmlRootElement 
@XmlAccessorType(XmlAccessType.FIELD) 
public class User { 

    String login; 

    @XmlJavaTypeAdapter(HalfDuplexXmlAdapter.class) 
    String password; 

    // getters and setters 
} 

所以這樣一來,密碼從客戶端發送到服務器的序列化和反序列化,但是當用戶從服務器發送到客戶端時,密碼不是序列化和/或反序列化的,所以不發送(空)。

相關問題