2011-09-26 20 views
1

我有一个Web服务器响应xml数据和使用它的客户端。 两者共享相同的域代码。其中一个域对象是这样的:通过扩展它们在Jaxb生成的类上添加/覆盖行为

@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER) 
@XmlRootElement(name = "image") 
public class Image { 

    private String filename; 
    private ImageTypeEnum type; 

    @XmlElement(name = "imageUri") 
    public String getAbsoluteUri() { 
     // some complex computation 
     return uri; 
    } 
} 

当我尝试解组服务器的响应到这个对象,因为有对绝对URI没有二传手,我没有imageUri在类。所以我向它是这样的:

public class FEImage extends Image{ 
private String imageUri; 
    public String getAbsoluteUri() { 
     return imageUri; 
    } 
    public void setAbsoluteUri(String imageUri) { 
     this.imageUri = imageUri; 
    } 
} 

我的ObjectFactory

@XmlRegistry 
public class ObjectFactory { 
    public Image createImage(){ 
     return new FEImage(); 
    } 
} 

我的代码来解组​​是在这里:

JAXBContext context = JAXBContext.newInstance(ObjectFactory.class); 
Unmarshaller unmarshaller = context.createUnmarshaller(); 
unmarshaller.setProperty("com.sun.xml.bind.ObjectFactory",new ObjectFactory());   
((JAXBElement)unmarshaller.unmarshal((InputStream) response.getEntity())).getValue(); 

然而,setAbsoluteUri似乎并没有被得到调用FEImage同时解组。当我在Image.java中添加虚拟setAbsoluteUri时,一切都按预期工作。

有人能告诉我如何干净地从Image.java延长?

回答

4

备注:我是EclipseLink JAXB (MOXy)的领导和JAXB 2 (JSR-222)专家组的成员。


甲JAXB实现不需要实例化对象时使用的ObjectFactory类。您可以配置实例可以使用@XmlType注释通过工厂类来完成:

@XmlType(factoryClass=ObjectFactory.class, factoryMethod="createImage") 
public class Image { 

    private String filename; 
    private ImageTypeEnum type; 

    @XmlElement(name = "imageUri") 
    public String getAbsoluteUri() { 
     // some complex computation 
     return uri; 
    } 
} 

如果你做到上面,那么你的JAXB实现将仍然使用Image类派生元数据,所以它不会解决你的问题。另一种方法是使用一个XmlAdapter这个用例:

更妙的是,当你的域对象上的属性没有一个二传手,你可以告诉你 JAXB实现(EclipseLink MOXy,地铁,阿帕奇JaxMe等)改为使用@XmlAccessorType(XmlAccessType.FIELD)使用字段(实例变量)访问:

@XmlAccessorType(XmlAccessType.FIELD) 
public class Image { 
} 

更新#1

如果你不能够修改域对象,那么你可能有兴趣在莫西的外部化的元数据。该扩展提供了一种通过XML的方式,为不能修改源的类提供JAXB元数据。

更多信息


更新#2 - 基于聊天的结果

图片

下面是Image类,我会用这个例子的实现。对于getAbsoluteUri()复杂的计算我只需添加前缀“CDN”的文件名:

package forum7552310; 

import javax.xml.bind.annotation.XmlAccessorType; 
import javax.xml.bind.annotation.XmlAccessType; 
import javax.xml.bind.annotation.XmlElement; 
import javax.xml.bind.annotation.XmlRootElement; 

@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER) 
@XmlRootElement(name = "image") 
public class Image { 

    private String filename; 
    private ImageTypeEnum type; 

    @XmlElement(name = "imageUri") 
    public String getAbsoluteUri() { 
     return "CDN" + filename; 
    } 

} 

binding.xml

下面是莫西约束力的文件我放在一起。在这个文件中我做了几件事情:

  • 设置XmlAccessorTypeFIELD
  • 马克绝对URI属性为XmlTransient,因为我们将要代替映射filename领域。
  • 指定XmlAdapter将与filename字段一起使用。这是应用在getAbsoluteUri()方法中完成的逻辑。

 

<?xml version="1.0"?> 
<xml-bindings 
    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm" 
    package-name="forum7552310"> 
    <java-types> 
     <java-type name="Image" xml-accessor-type="FIELD"> 
      <java-attributes> 
       <xml-element java-attribute="filename" name="imageUri"> 
        <xml-java-type-adapter value="forum7552310.FileNameAdapter"/> 
       </xml-element> 
       <xml-transient java-attribute="absoluteUri"/> 
      </java-attributes> 
     </java-type> 
    </java-types> 
</xml-bindings> 

FileNameAdapter

下面是适用相同的名字算法作为getAbsoluteUri()方法XmlAdapter的实现:

package forum7552310; 

import javax.xml.bind.annotation.adapters.XmlAdapter; 

public class FileNameAdapter extends XmlAdapter<String, String> { 

    @Override 
    public String marshal(String string) throws Exception { 
     return "CDN" + string; 
    } 

    @Override 
    public String unmarshal(String adaptedString) throws Exception { 
     return adaptedString.substring(3); 
    } 

} 

演示

下面是演示代码演示如何创建的JAXBContext时应用绑定文件:

package forum7552310; 

import java.io.File; 
import java.util.HashMap; 
import java.util.Map; 

import javax.xml.bind.JAXBContext; 
import javax.xml.bind.Marshaller; 
import javax.xml.bind.Unmarshaller; 

import org.eclipse.persistence.jaxb.JAXBContextFactory; 

public class Demo { 

    public static void main(String[] args) throws Exception { 
     Map<String, Object> properties = new HashMap<String, Object>(1); 
     properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "forum7552310/binding.xml"); 
     JAXBContext jc = JAXBContext.newInstance(new Class[] {Image.class}, properties); 

     File xml = new File("src/forum7552310/input.xml"); 
     Unmarshaller unmarshaller = jc.createUnmarshaller(); 
     Image image = (Image) unmarshaller.unmarshal(xml); 

     System.out.println(image.getAbsoluteUri()); 

     Marshaller marshaller = jc.createMarshaller(); 
     marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
     marshaller.marshal(image, System.out); 
    } 
} 

JAXB。性能

您需要包括一个名为jaxb.properties在同一个包中的文件,内容如下为您Image类:

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory 

的input.xml

这里是XML我用的输入:

<?xml version="1.0" encoding="UTF-8"?> 
<image> 
    <imageUri>CDNURI</imageUri> 
</image> 

输出

这里是从运行演示代码的输出:

CDNURI 
<?xml version="1.0" encoding="UTF-8"?> 
<image> 
    <imageUri>CDNURI</imageUri> 
</image> 
+0

,因为我没有过Image.java控制可能是不可能的。这可以在FEImage.java上完成吗?此外,请注意absoluteUri不是Image.java中的实例级字段。它在飞行中生成。 – Sam

+0

@Sam - 我在答案中增加了更多细节。 –

+0

谢谢,这看起来很有希望。我已经开始实现这个,但继续运行到javax.xml.bind.JAXBException:不支持属性“eclipselink-oxm-xml”。我在与FEImage.java相同的位置指定了jaxb.properties,它是com.example.fe.domain.image。我也试过把它放在上面一层,也放在类路径中,但没有用。任何提示? – Sam

相关问题