2011-11-06 48 views
3

根據文檔JAXB工廠方法沒有參數。有沒有JAXB實現允許我創建一個工廠方法,該工廠方法接收作爲參數的我需要創建的對象的類? 碰巧我所有的JAXB對象都遵循相同的創建模式(特定的字節代碼工具),因此我想將其封裝在一個工廠方法中,該工廠方法以參數方式創建JAXB對象的類,以這種方式避免爲每個JAXB類創建不同的工廠方法,基本上完成相同的事情。用類創建參數化JAXB工廠方法

我發現有人在OTN論壇上提出同樣的問題:https://forums.oracle.com/forums/thread.jspa?messageID=9969927#9969927,但還沒有提出真正的答案。

感謝所有幫助

+1

事情是這樣的:http://download.oracle.com/javase/6/docs/api/javax/xml/bind/ JAXB.html#解組%28java.io.InputStream,%20java.lang.Class%29? –

+0

如果工廠方法是自動生成的,那麼爲什麼要關心有多少個? – skaffman

+0

嗨@skaffman,我使用工廠方法,因爲我需要以特定方式實例化解組對象。這些工廠方法不是自動生成的。 – Sergio

回答

2

這是目前沒有使用標準的API JAXB可能。我已經輸入了以下增強請求有這種行爲加入到EclipseLink JAXB (MOXy)

莫西具體解決方案

你可以在EclipseLink JAXB (MOXy)充分利用@XmlCustomizer擴展自定義對象如何被實例化。這個機制被用來調整MOXy的底層元數據。

CommonFactory

import java.util.Date; 

public class CommonFactory { 

    public static Object create(Class<?> clazz) { 
     if(Foo.class == clazz) { 
      return new Foo(new Date()); 
     } else if(Bar.class == clazz) { 
      return new Bar(new Date()); 
     } 
     return null; 
    } 

} 

讓Foo.class

Foo類,例外的是,我們將使用@XmlCustomizer批註指定一個DescriptorCustomizer,我們將以正常註解用來調整MOXY的元數據。

import java.util.Date; 
import javax.xml.bind.annotation.*; 
import org.eclipse.persistence.oxm.annotations.XmlCustomizer; 

@XmlRootElement 
@XmlType(factoryClass=CommonFactory.class, factoryMethod="create") 
@XmlAccessorType(XmlAccessType.FIELD) 
@XmlCustomizer(FactoryCustomizer.class) 
public class Foo { 

    private Date creationDate; 
    private Bar bar; 

    // Non-default constructor 
    public Foo(Date creationDate) { 
     this.creationDate = creationDate; 
    } 

} 

酒吧

同樣,我們將使用@XmlCustomizer註釋引用我們在Foo類做了同樣的DescriptorCustomizer

import java.util.Date; 
import javax.xml.bind.annotation.*; 
import org.eclipse.persistence.oxm.annotations.XmlCustomizer; 

@XmlType(factoryClass=CommonFactory.class, factoryMethod="create") 
@XmlAccessorType(XmlAccessType.FIELD) 
@XmlCustomizer(FactoryCustomizer.class) 
public class Bar { 

    private Date creationDate; 

    // Non-default constructor 
    public Bar(Date creationDate) { 
     this.creationDate = creationDate; 
    } 

} 

FactoryCustomizer

莫西有InstantiationPolicy的概念來建立新的對象。在這個例子中,我們將在我們自己的實例InstantiationPolicy交換,可以使用參數化的工廠方法:

import org.eclipse.persistence.config.DescriptorCustomizer; 
import org.eclipse.persistence.descriptors.ClassDescriptor; 
import org.eclipse.persistence.exceptions.DescriptorException; 
import org.eclipse.persistence.internal.descriptors.InstantiationPolicy; 
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper; 
import org.eclipse.persistence.internal.sessions.AbstractSession; 

public class FactoryCustomizer implements DescriptorCustomizer{ 

    @Override 
    public void customize(ClassDescriptor descriptor) throws Exception { 
     descriptor.setInstantiationPolicy(new MyInstantiationPolicy(descriptor)); 
    } 

    private static class MyInstantiationPolicy extends InstantiationPolicy { 

     public MyInstantiationPolicy(ClassDescriptor descriptor) { 
      InstantiationPolicy defaultInstantiationPolicy = descriptor.getInstantiationPolicy(); 
      this.factoryClassName = defaultInstantiationPolicy.getFactoryClassName(); 
      this.factoryClass = defaultInstantiationPolicy.getFactoryClass(); 
      this.methodName = defaultInstantiationPolicy.getMethodName(); 
     } 

     @Override 
     public void initialize(AbstractSession session) throws DescriptorException { 
      super.initialize(session); 
     } 

     @Override 
     protected void initializeMethod() throws DescriptorException { 
      Class<?>[] methodParameterTypes = new Class[] {Class.class}; 
      try { 
       this.method = PrivilegedAccessHelper.getMethod(factoryClass, methodName, methodParameterTypes, true); 
      } catch (NoSuchMethodException e) { 
       throw new RuntimeException(e); 
      } 
     } 

     @Override 
     public Object buildNewInstance() throws DescriptorException { 
      Object[] parameters = new Object[] {this.descriptor.getJavaClass()}; 
      try { 
       return PrivilegedAccessHelper.invokeMethod(method, factory, parameters); 
      } catch (Exception e) { 
       throw new RuntimeException(e); 
      } 
     } 

    } 

} 

演示

import java.io.StringReader; 
import javax.xml.bind.*; 

public class Demo { 

    public static void main(String[] args) throws Exception { 
     JAXBContext jc = JAXBContext.newInstance(Foo.class); 

     Unmarshaller unmarshaller = jc.createUnmarshaller(); 
     Foo foo = (Foo) unmarshaller.unmarshal(new StringReader("<foo><bar/></foo>")); 

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

} 

輸出

<?xml version="1.0" encoding="UTF-8"?> 
<foo> 
    <creationDate>2011-11-08T12:35:43.198</creationDate> 
    <bar> 
     <creationDate>2011-11-08T12:35:43.198</creationDate> 
    </bar> 
</foo> 

更多信息

+1

嗨!,是的,我有興趣瞭解MOXY特定的解決方案,這是我現在使用的。 – Sergio

+1

@Sergio - 我添加了一種方法,你可以使用MOXY來做到這一點。 –