Поддерживает ли JAXB значения схемы по умолчанию? - PullRequest
8 голосов
/ 24 марта 2011

У меня есть схема, которая определяет значения по умолчанию для элементов и атрибутов.Я пытаюсь проанализировать документ с использованием JAXB на основе этой схемы, но JAXB не устанавливает значения по умолчанию.Любые идеи о том, как заставить JAXB соблюдать значения по умолчанию из схемы?

example.xsd:

<?xml version="1.0" encoding="UTF-8"?><xs:schemaxmlns:xs="http://www.w3.org/2001/XMLSchema" 
targetNamespace="http://www.example.org/example" 
xmlns:tns="http://www.example.org/example">

<xs:element name="root" type="tns:rootType"/>

<xs:complexType name="rootType">
    <xs:sequence>
        <xs:element name="child" type="tns:childType"/>
    </xs:sequence>
</xs:complexType>

<xs:complexType name="childType">
    <xs:sequence>
        <xs:element name="childVal" type="xs:string" default="defaultElVal"/>
    </xs:sequence>
    <xs:attribute name="attr" type="xs:string" default="defaultAttrVal"/>
</xs:complexType>

example1.xml

<?xml version="1.0" encoding="UTF-8"?>
<tns:root xmlns:tns="http://www.example.org/example" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.org/example example.xsd ">
  <child>
    <childVal/>
  </child>
</tns:root>

TestParser.java

package test;  
import java.io.File;  
import javax.xml.XMLConstants;  
import javax.xml.bind.JAXBContext;  
import javax.xml.bind.Unmarshaller;  
import javax.xml.validation.Schema;  
import javax.xml.validation.SchemaFactory;  
public class TestParser {    
    public static void main(String[] pArgs) {  
        try {  
            JAXBContext context = JAXBContext.newInstance(RootElement.class);  
            Unmarshaller unmarshaller = context.createUnmarshaller();  

            SchemaFactory schemaFac = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
            Schema sysConfigSchema = schemaFac.newSchema(
                    new File("example.xsd"));
            unmarshaller.setSchema(sysConfigSchema);
            RootElement root = (RootElement)unmarshaller.unmarshal(
                    new File("example1.xml"));
            System.out.println("Child Val: " + root.getChild().getChildVal());
            System.out.println("Child Attr: " + root.getChild().getAttr());
        } catch (Exception e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
    }
}

RootElement.java

package test;  
import javax.xml.bind.annotation.XmlRootElement;  

@XmlRootElement(name="root", namespace="http://www.example.org/example")  
public class RootElement {  

    private ChildEl child;  

    public RootElement() {}  

    public ChildEl getChild() {
        return child;
   }

    public void setChild(ChildEl pChild) {
        this.child = pChild;
    }
}

ChildEl.java

package test;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="child")
public class ChildEl {

    private String attr;
    private String childVal;

    public ChildEl() {};

    @XmlAttribute
    public String getAttr() {
        return attr;
    }
    public void setAttr(String pAttr) {
        this.attr = pAttr;
    }

    public String getChildVal() {
        return childVal;
    }
    public void setChildVal(String pVal) {
        this.childVal = pVal;
    }

}

Ответы [ 3 ]

11 голосов
/ 24 марта 2011

Значение элемента по умолчанию

Чтобы получить значение по умолчанию для свойства элемента, необходимо аннотировать его следующим образом:

@XmlElement(defaultValue="defaultElVal")
public String getChildVal() {
    return childVal;
}

Значение атрибута по умолчанию

Если вы используете EclipseLink JAXB (MOXy) , вы получите значение атрибута по умолчанию, используя предоставленный вами код. В реализации Metro JAXB может быть ошибка, которая мешает этому работать. Обратите внимание, я веду реализацию MOXy.

<Ч />

Альтернативный подход

Следующий код должен работать с любой реализацией JAXB, не требуя каких-либо изменений кода в вашей модели. Вы можете сделать следующее и использовать SAXSource:

import java.io.File;  
import java.io.FileInputStream;

import javax.xml.XMLConstants;  
import javax.xml.bind.JAXBContext;  
import javax.xml.bind.Unmarshaller;  
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.sax.SAXSource;
import javax.xml.validation.Schema;  
import javax.xml.validation.SchemaFactory;  

import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
public class TestParser {    
    public static void main(String[] pArgs) {  
        try {  
            JAXBContext context = JAXBContext.newInstance(RootElement.class);  
            Unmarshaller unmarshaller = context.createUnmarshaller();  

            SchemaFactory schemaFac = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
            Schema sysConfigSchema = schemaFac.newSchema(
                    new File("example.xsd"));

            SAXParserFactory spf = SAXParserFactory.newInstance();
            spf.setNamespaceAware(true);
            spf.setSchema(sysConfigSchema);
            XMLReader xmlReader = spf.newSAXParser().getXMLReader();
            SAXSource source = new SAXSource(xmlReader, new InputSource(new FileInputStream("example1.xml")));
            RootElement root = (RootElement)unmarshaller.unmarshal(
                    source);
            System.out.println("Child Val: " + root.getChild().getChildVal());
            System.out.println("Child Attr: " + root.getChild().getAttr());
        } catch (Exception e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
    }
}
4 голосов
/ 31 октября 2011

Я считаю то, что вы пытаетесь сделать, разумным, особенно для достижения гармонии между Атрибутом и Простыми Элементами.Это кажется странным, но, похоже, разработчики jaxb2 решили добавить дополнительный набор расширений, которые вы должны добавить, чтобы получить желаемое поведение.См .:

(я бы скорее увидел более естественное поведение по умолчанию и согласованность между Атрибутами и Элементами хотя бы простых типов - безнеобходимо зарегистрировать плагин. Затем предоставьте плагин для особых случаев. Мои единственные ребята, почему это не было сделано, или обратная совместимость - предположение.)

По умолчанию jaxb2-commonsПлагин value относится к дополнительным командам (и банкам), которые вы добавляете в xjc, что, в свою очередь, добавляет поведение по умолчанию в поле.В моем случае:

public String getScalarOptionalMaxAndDefaultString() {
    if (scalarOptionalMaxAndDefaultString == null) {
        return "def val 1";
    } else {
        return scalarOptionalMaxAndDefaultString;
    }   
}

(где, конечно, условная нулевая проверка представляет значение по умолчанию или нет.)

Использование Блейза Дафана кажется практичнымобойти.В зависимости от характера вашего документа XML, это может быть идеально.

Тем не менее, похоже, что этот плагин Default Value может переместить решение в процесс сборки и не увидеть изменений в вашем коде (при условии, что вы используете Dom, в отличие от предложенного Блейзом синтаксического анализатора Sax).

Похоже, что плагин значения по умолчанию решит проблему и, возможно, обеспечит дополнительную расширяемость (не требует такой расширенной настройки) в маловероятном случае, когда вам потребуется еще более программный контроль значений по умолчанию с запущенным xjc.

Вот фрагмент конфигурации maven на случай, если это поможет:

  <plugin>
    <groupId>org.jvnet.jaxb2.maven2</groupId>
    <artifactId>maven-jaxb2-plugin</artifactId>
    <version>0.8.0</version>
    <executions>
      <execution>
        <phase>generate-sources</phase>
        <goals>
          <goal>generate</goal>
        </goals>
        <configuration>
            <args>
                <arg>-Xdefault-value</arg>
            </args>
            <plugins>
                <plugin>
                    <groupId>org.jvnet.jaxb2_commons</groupId>
                    <artifactId>jaxb2-default-value</artifactId>
                    <version>1.1</version>
                </plugin>
            </plugins>
        </configuration>
      </execution>
    </executions>
    <configuration><schemaDirectory>src/test/resources</schemaDirectory></configuration>
  </plugin>
1 голос
/ 26 июля 2017

Другим способом установки значения по умолчанию может быть функция beforeMarshal (Marshaller marshaller):

private void beforeMarshal(Marshaller marshaller) {
    childVal = (null == getChildVal) ? CHILD_VAL_DEFAULT_VALUE : childVal; }
...