문제

I am currently trying to unmarshall the following XML file using the DynamicJaxbContext from MOXy:

<?xml version="1.0" encoding="UTF-8"?>
<request xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://somehost.com/schema_schedule_request.xsd">
    <header>
        <originator>MySatelliteCompany</originator>
        <recipient>Recipient</ recipient>
        <schedule_valid_from>2008-12-17T00:00:00Z</schedule_valid_from>
        <schedule_valid_to>2008-12-18T00:00:07Z</schedule_valid_to>
        <request_reference>HGT4285T3</request_reference>
        <generation_time>2008-12-16T08:24:00Z</generation_time>
     </header>
     <body>
         <schedule_request>
         <start_time>2008-12-17T09:30:47Z</start_time>
         <end_time>2008-12-17T09:33:47Z</end_time>
         <satellite_name>MySat</satellite_name>
         </schedule_request>
     </body>
</request>

It works but the dynamically created Java classes' properties do not correspond to the fields given in the XML. For example: <satellite_name> is unmarshalled to "satelliteName". This makes writing a custom binding file for my backend API quite difficult, because I would have to first either unmarshall all XML files I will get as Input and manually write down the corresponding property names or write another helper app which does this for me.

Is there any way to change this MOXy behavior so it unmarshalls the field names correctly as they are in the XML?

ADDITION: So I found why this is in the MOXy Documentation:

XML names found in the metadata (complex type names, element names, attribute names) will be translated to Java identifiers according to the algorithms described in "Appendix D: Binding XML Names to Java Identifiers" of the Java Architecture for XML Binding (JAXB) 2.2 Specification (http://jcp.org/en/jsr/detail?id=222). - See more at: http://www.eclipse.org/eclipselink/documentation/2.4/moxy/dynamic_jaxb001.htm#BABCDJDF

but my principle question still stands: is there any way to shut this off or modify this behavior?

도움이 되었습니까?

해결책

Your ADDITION is correct, MOXy isn't unmarshalling wrong property names, it just unmarshals to property names that correspond to what the mapped property/field names would be in the generated classes.

What the Solution Should Be

binding.xml

The default XML Schema to Java naming rules in JAXB is to remove the _. You can supply a binding file to have this behaviour be different.

<jaxb:bindings 
    xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
    version="2.1">
    <jaxb:globalBindings underscoreBinding="asCharInWord"/>
</jaxb:bindings>

Demo

Using MOXy's Dynamic JAXB, below is an example of how you can leverage the bindings file.

import java.io.File;
import java.util.*;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.dynamic.DynamicEntity;
import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory;

public class Demo {

    public static void main(String[] args) throws Exception {
        StreamSource schemaSource = new StreamSource("src/forum20146935/schema.xsd");
        Map<String, Object> properties = new HashMap<String, Object>(1);
        properties.put(DynamicJAXBContextFactory.EXTERNAL_BINDINGS_KEY, new StreamSource("src/forum20146935/binding.xml"));
        JAXBContext jc = DynamicJAXBContextFactory.createContextFromXSD(schemaSource, null, Demo.class.getClassLoader(), properties);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum20146935/input.xml");
        DynamicEntity root = (DynamicEntity) unmarshaller.unmarshal(xml);
        System.out.println(root.get("foo_bar"));
    }

}

Why Didn't it Work?

As I mentioned earlier MOXy will base the dynamic property name based on the corresponding mapped field/property generated by XJC. This happens to look something like where the property name has the _ but the corresponding mapped field does not.

@XmlElement(name = "foo_bar", required = true)
protected String fooBar;

public String getFoo_Bar() {
    return fooBar;
}

public void setFoo_Bar(String value) {
    this.fooBar = value;
}

What you Could Do Instead

  1. Use the transformed key name.
  2. You could use the getValueByXPath functionality on the MOXy JAXBContext to interact with the objects in a more XML like way.

    import java.io.File;
    import java.util.*;
    
    import javax.xml.bind.*;
    import javax.xml.transform.stream.StreamSource;
    
    import org.eclipse.persistence.dynamic.DynamicEntity;
    import org.eclipse.persistence.jaxb.JAXBHelper;
    import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory;
    
    public class Demo {
    
        public static void main(String[] args) throws Exception {
            StreamSource schemaSource = new StreamSource("src/forum20146935/schema.xsd");
            Map<String, Object> properties = new HashMap<String, Object>(1);
            properties.put(DynamicJAXBContextFactory.EXTERNAL_BINDINGS_KEY, new StreamSource("src/forum20146935/binding.xml"));
            JAXBContext jc = DynamicJAXBContextFactory.createContextFromXSD(schemaSource, null, Demo.class.getClassLoader(), properties);
    
            Unmarshaller unmarshaller = jc.createUnmarshaller();
            File xml = new File("src/forum20146935/input.xml");
            DynamicEntity root = (DynamicEntity) unmarshaller.unmarshal(xml);
    
            String fooBar = JAXBHelper.getJAXBContext(jc).getValueByXPath(root, "foo_bar/text()", null, String.class);
            System.out.println(fooBar);
        }
    
    }
    
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top