0

I'm trying to create a simple un/marshalling with Java for my xml file. I've found some good examples online and have tried to follow them, but it doesn't work for me. Here are two links that implement something very similar to what I want: http://www.mkyong.com/java/jaxb-hello-world-example/ and convert xml to java object using jaxb (unmarshal)

When I run my code I get this:

Exception in thread "main" com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 6 counts of IllegalAnnotationExceptions
Property value1 is present but not specified in @XmlType.propOrder
this problem is related to the following location:
    at public java.lang.String Location.getValue1()
    at Location
    at public java.util.List Locations.getLocation()
    at Locations
Property value2 is present but not specified in @XmlType.propOrder
this problem is related to the following location:
    at public int Location.getValue2()
    at Location
    at public java.util.List Locations.getLocation()
    at Locations
Property value3 is present but not specified in @XmlType.propOrder
this problem is related to the following location:
    at public java.lang.String Location.getValue3()
    at Location
    at public java.util.List Locations.getLocation()
    at Locations
Property Value1 appears in @XmlType.propOrder, but no such property exists. Maybe you meant value1?
this problem is related to the following location:
    at Location
    at public java.util.List Locations.getLocation()
    at Locations
Property Value2 appears in @XmlType.propOrder, but no such property exists. Maybe you meant value2?
this problem is related to the following location:
    at Location
    at public java.util.List Locations.getLocation()
    at Locations
Property Value3 appears in @XmlType.propOrder, but no such property exists. Maybe you meant value3?
this problem is related to the following location:
    at Location
    at public java.util.List Locations.getLocation()
    at Locations

at com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:91)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:445)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:277)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:124)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1123)
at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:147)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:247)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:234)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:462)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:641)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:584)
at main.main(main.java:18)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

My xml is this:

<?xml version="1.0" encoding="utf-8" ?>
<Locations>
    <Location>
        <Value1>one</Value1>
        <Value2>1</Value2>
        <Value3>a</Value3>
    </Location>
    <Location>
        <Value1>two</Value1>
        <Value2>2</Value2>
        <Value3>b</Value3>
    </Location>
    <Location>
        <Value1>three</Value1>
        <Value2>3</Value2>
        <Value3>c</Value3>
    </Location>
</Locations>

Here are my two object classes:

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.List;


@XmlRootElement
public class Locations {
    List<Location> location;

    @XmlElement(name="Location")
    public List<Location> getLocation() {
        return location;
    }

    public void setLocation(List<Location> myLocation) {
        this.location = myLocation;
    }
}



import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;

@XmlType(propOrder = {"Value1", "Value2", "Value3"})
public class Location {
    String Value1;
    int Value2;
    String Value3;

    public String getValue1() {
        return Value1;
    }

    @XmlElement
    public void setValue1(String Value1) {
        this.Value1 = Value1;
    }

    public int getValue2() {
        return Value2;
    }

    @XmlElement
    public void setValue2(int Value2) {
        this.Value2 = Value2;
    }

    public String getValue3() {
        return Value3;
    }

    @XmlElement
    public void setValue3(String Value3) {
        this.Value3 = Value3;
    }
}

And here's my main:

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.*;
import java.io.File;

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

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("C:\\files\\Settings.xml");
        Locations locations = (Locations) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(locations, System.out);
    }
}
Community
  • 1
  • 1
reubonwry
  • 317
  • 4
  • 15

2 Answers2

2

Basically, you have a case problem here - within the XML file, the tags all start with an uppercase letter. In the java classes, you have annotated the setters with @XmlElement, thus instructing JAXB to take these for marshalling/unmarshalling. However, according to the JavaBeans specification, Section 8.3, the setter method setValue1 implies that the property is named value1 (lowercase!).

So you have to explicitly tell JAXB the correct name (case-sensitive!) of the property within the XML that is to be mapped to a property of the Java class. In your case for example, you have to tell that Value1 must be mapped to the Java property value1. You do this by annotating the setter method with @XmlElement(name="Value1"). The values of propOrder must relate to the properties of the Java class, not to the XML tags.

The following worked for me:

   public static void main(String[] args) throws JAXBException {
        JAXBContext jc = JAXBContext.newInstance(Locations.class, Location.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("D:\\temp\\Settings.xml");
        Locations locations = (Locations) unmarshaller.unmarshal(xml);

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

    @XmlRootElement(name = "Locations")
    private static class Locations {
        List<Location> location;

        public List<Location> getLocation() {
            return location;
        }

        @XmlElement(name = "Location")
        public void setLocation(List<Location> myLocation) {
            this.location = myLocation;
        }
    }

    @XmlType(propOrder = { "value1", "value2", "value3" })
    private static class Location {
        String Value1;
        int Value2;
        String Value3;

        public String getValue1() {
            return Value1;
        }

        @XmlElement(name = "Value1")
        public void setValue1(String Value1) {
            this.Value1 = Value1;
        }

        public int getValue2() {
            return Value2;
        }

        @XmlElement(name = "Value2")
        public void setValue2(int Value2) {
            this.Value2 = Value2;
        }

        public String getValue3() {
            return Value3;
        }

        @XmlElement(name = "Value3")
        public void setValue3(String Value3) {
            this.Value3 = Value3;
        }
    }
beosign
  • 433
  • 5
  • 10
  • When I ran your code above, it worked just fine. But when I started swapping out the xml tag names (e.g. "Value1"), I got weird exceptions again. It now is working when I changed all my xml tag names to completely match the case as the values in the propOrder. But what's strange is that in the above code, it uses xml which has mismatching cases between the xml and the propOrder and it works just fine. Anyways, thanks! – reubonwry Aug 31 '15 at 14:37
  • Note that the names of `propOrder` within the `@XmlType`annotation do not correspond to those in the XML file but to the properties in the Java class. Since you are using property based access, they must correspond to the name of the getter/setter – beosign Aug 31 '15 at 14:47
1

At class Location Use

@XmlType(propOrder = {"value1", "value2", "value3"})

and at class Locations

@XmlRootElement(name = "Locations")

I would also recommend sticking to the Java naming convention of using lowercase first letter for variables (uppercase for class names). E.g. Value1 to value1, Value2 to value2 and Value3 to value3

Manos Nikolaidis
  • 21,608
  • 12
  • 74
  • 82