2016-11-20 5 views
0

Ich arbeite an einer Konfigurations-XML-Datei, die ich gerne dynamisch wäre.JAXB Vererbung dynamisch benannte Tags

Ich habe die folgenden Klassen:

Repository:

@XmlAccessorType(XmlAccessType.FIELD) 
@XmlRootElement(name = "repository") 
public class Repository 
     implements Serializable 
{ 

    @XmlElement(name = "custom-configuration") 
    private CustomConfiguration customConfiguration; 

    ... 
    // Constructor 

    // Getters and setters 
} 

CustomConfiguration:

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

FooBarConfiguration:

@XmlAccessorType(XmlAccessType.FIELD) 
@XmlRootElement(name = "foo-bar-configuration") 
public class FooBarConfiguration extends CustomConfiguration 
{ 

    @XmlAttribute 
    private String bucket; 

    @XmlAttribute 
    private String key; 


    public FooBarConfiguration() 
    { 
    } 

    public String getBucket() 
    { 
     return bucket; 
    } 

    public void setBucket(String bucket) 
    { 
     this.bucket = bucket; 
    } 

    public String getKey() 
    { 
     return key; 
    } 

    public void setKey(String key) 
    { 
     this.key = key; 
    } 

} 

Dies ist, was ich haben möchte:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<repository id="test-repository"> 
    <foo-bar-configuration bucket="test-bucket" key="test-key"/> 
    <group/> 
</repository> 

Dies ist, was ich bin immer statt:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<repository id="test-repository"> 
    <customConfiguration xsi:type="fooBarConfiguration" bucket="test-bucket" key="test-key" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/> 
    <group/> 
</repository> 

Irgendwelche Ideen, wie dies zu erreichen?

Antwort

1

Wie gewünscht, hier ist ein Praxisbeispiel.

Schema declares and abstract element einiger Basistyp:

<xsd:element name="AbstractQueryExpression" 
       type="fes:AbstractQueryExpressionType" abstract="true"/> 

This is how it's used:

<xsd:complexType name="GetPropertyValueType"> 
     <xsd:complexContent> 
     <xsd:extension base="wfs:BaseRequestType"> 
      <xsd:sequence> 
       <xsd:element ref="fes:AbstractQueryExpression"/> 
      </xsd:sequence> 
      <xsd:attribute name="valueReference" type="xsd:string" 
       use="required"/> 
      <xsd:attribute name="resolvePath" type="xsd:string"/> 
      <xsd:attributeGroup ref="wfs:StandardPresentationParameters"/> 
      <xsd:attributeGroup ref="wfs:StandardResolveParameters"/> 
     </xsd:extension> 
     </xsd:complexContent> 
    </xsd:complexType> 

die in den folgenden Java-Code-Ergebnisse:

@XmlElementRef(name = "AbstractQueryExpression", namespace = "http://www.opengis.net/fes/2.0", type = JAXBElement.class) 
protected JAXBElement<?> abstractQueryExpression; 

Another schema declares an element which may substitute the original element:

<xsd:element name="StoredQuery" type="wfs:StoredQueryType" 
     substitutionGroup="fes:AbstractQueryExpression"/> 

In ObjectFactory sieht das wie folgt aus:

@XmlElementDecl(namespace = "http://www.opengis.net/wfs/2.0", name = "StoredQuery", substitutionHeadNamespace = "http://www.opengis.net/fes/2.0", substitutionHeadName = "AbstractQueryExpression") 
public JAXBElement<StoredQueryType> createStoredQuery(StoredQueryType value) { 
    return new JAXBElement<StoredQueryType>(_StoredQuery_QNAME, StoredQueryType.class, null, value); 
} 

Dieser Mechanismus verwendet werden kann, "Erweiterungspunkte" zu implementieren. Sie deklarieren und verwenden ein abstraktes/generisches "substitution head" -Element und in anderen Schemas können bestimmte Elemente es ersetzen.

Hoffe, das hilft.

+0

Das Problem ist, ich benutze keine XSD. Ich habe Klassen, die die 'CustomConfiguration' erweitern können, die nicht bekannt sind. Sie können oder sind nicht auf dem Klassenpfad, also kann ich nicht so einfach einen 'Objektmapper' schreiben (weil ich vorher die Namen dieser Klassen kennen müsste). Irgendwelche anderen Vorschläge? – carlspring

+0

@carlspring Sie benötigen keine XSD und müssen die Klassen auch nicht im Voraus kennen. Platzieren Sie 'ObjectFactory', wo Ihre Erweiterungsklassen sind. Verwenden Sie es beim Erstellen des JAXB-Kontexts in Runtime. Sie müssen diese Klassen nicht in der Kompilierzeit kennen. – lexicore

+0

Denkst du, du könntest vielleicht meinen Diff hier kurz anschauen: https://github.com/strongbox/strongbox/pull/183/files und sag mir, was ich falsch mache? (Wenn Sie den Code erstellen möchten, überprüfen Sie bitte hier: https://github.com/strongbox/strongbox/wiki/Building-the-code). Dies ist der Fehler, den ich bekomme: https://github.com/strongbox/strongbox/pull/183/commits/9bdc666c32e7ba04df2e1befe7655050c1652bc9. – carlspring

1

Sie sollten durch die Elementnamen mit @XmlElementRef, zum Beispiel Marschall der Lage sein:

@XmlElementRef 
private CustomConfiguration customConfiguration; 

Hier ist ein Beispiel von Blaise Doughan: http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-substitution.html

Javadoc: https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/annotation/XmlElementRef.html

+0

Das sieht nach einer guten Idee aus. Das Problem ist, dass die Idee ist dies - dieses Feld ist hier, so dass benutzerdefinierte Implementierungen vorgenommen werden können. Ich weiß nicht, was sie sein werden. Sie liegen außerhalb des Anwendungsbereichs unserer Anwendung. Daher weiß ich nicht, wie die Namen des Feldes lauten werden. Deshalb versuche ich, dieses Aussehen so generisch zu machen. Ist das möglich? – carlspring

+1

@carlspring Sie können '@XmlElementRef protected JAXBElement ' ausführen.Ihre Erweiterungsmodule müssen eine 'ObjectFactory' mit' @XmlElementDecl (substitutionHeadName = "custom-configuration") 'bereitstellen. Dieses Patern wird als Substitutionsgruppe bezeichnet. Sie sagen grundsätzlich, dass Sie 'FooBarConfiguration'' 'CustomConfiguration' ersetzen können. – lexicore

+0

@lexicore: Würde es Ihnen etwas ausmachen, ein kurzes Beispiel für diesen Fall zu nennen? Vor allem die Fabrik Teil ... – carlspring

Verwandte Themen