@XmlTransient用于序列化但不用于反序列化?

时间:2012-05-11 13:45:19

标签: java rest jaxb persistence jpa-2.0

有没有办法配置@XmlTransient JPA2.0注释,它只会在Java-Object序列化为xml时阻塞JAXB机制,而不是在传入XML转换为java对象时阻塞JAXB机制?

背景:我有一个REST api,它说XML。有一个端点可以创建一个新的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();
}
}

因此,当我使用XmlTransient标记getDataPart()时,将忽略传入byte []的数据并将其设置为null - >它丢了。 任何人都知道如何指定XmlTransient的方向?

4 个答案:

答案 0 :(得分:1)

我必须自己回答这个问题=) 我通过使用自定义XmlAdapter来解决这个问题,该自定义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();
    }
}

此解决方案可以正常工作。但是有一个缺点:其中一个目的是不让hibernate在处理/加载附件数据时加载二进制数据。但那不是它的工作原理。在这种情况下,二进制数据由hibernate加载,因为它被发送到XMLAdapter但未转换为base64 :(

答案 1 :(得分:0)

我认为你的问题不是“是的,序列化它,而是不反序列化”,而是:传输数据客户端 - &gt;服务器,但不是服务器 - &gt;客户。您希望您的服务器反序列化传入的byte[]数据,对吗?你只是不想(总是?)在返回实体时将其发送出去。

如果是这种情况,您可以在发送实体之前将其设置为null。在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();
}

答案 2 :(得分: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>

如果你反序列化(使用相同的类定义),unmarshaller将不会设置bar(因为它找不到setter)。

答案 3 :(得分:0)

汉斯,我有同样的问题。你的回答让我以正确的方式。 如果问题只是序列化,那就可以解决问题:

public class HalfDuplexXmlAdapter extends XmlAdapter<String, String> {

    @Override
    public String unmarshal(String value) throws Exception {
        return value;
    }

    @Override
    public String marshal(String value) throws Exception {
        //ignore marshall so you have half duplex
        return null;
    }

}

然后以这种方式使用它:

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

    String login;

    @XmlJavaTypeAdapter(HalfDuplexXmlAdapter.class)
    String password;

    // getters and setters
}

这样,从客户端发送到服务器的密码被序列化和反序列化,但是当用户从服务器发送到客户端时,密码未被序列化和/或反序列化,因此不会被发送(null)。