I have looked through the jaxb and java changelogs between these two versions and have come up empty handed.
In 8u45 this code works fine,
package-info.java
#javax.xml.bind.annotation.XmlSchema(
namespace = "http://www.example.org",
elementFormDefault = XmlNsForm.QUALIFIED
) package com.rezometry.fw.net.soap;
import javax.xml.bind.annotation.XmlNsForm;
Foo.java
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlAccessorType( XmlAccessType.FIELD)
#XmlRootElement(name = "foo")
public class Foo {
#XmlElement( name = "bar", required = true )
public String bar;
}
Test.java
import javax.xml.transform.stream.StreamSource;
import javax.xml.bind.JAXB;
import java.io.StringReader;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
#Test public void testJaxB(){
Foo sample = JAXB.unmarshal( new StreamSource( new StringReader( "<foo><bar>bar1</bar></foo>" ) ), Foo.class );
assertThat( sample.bar, is("bar1") );
}
Yet in 8u111 sample.bar is null. I have read the various other answers regarding missing namespaces in the xml document, but I want to make sure going forward I am not patching over a bug that might be changed later.
Im am seeing this happen in intellij and the only difference in the set up is what version of java I am using. All other libraries are identical.
Related
Is it possible to directly unmarshal a list of wrapped elements into a List<String> in JAXB?
For example I have a XML like:
<TEST>
<MIME_INFO>
<MIME>
<MIME_SOURCE>foo.png</MIME_SOURCE>
<MIME_PURPOSE>normal</MIME_PURPOSE>
</MIME>
<MIME>
<MIME_SOURCE>bar.png</MIME_SOURCE>
<MIME_PURPOSE>normal</MIME_PURPOSE>
</MIME>
</MIME_INFO>
</TEST>
So would it be possible to directly unmarshal this XML file into a List<String> only containing { "foo.png", "bar.png" }?
I know that you could create a class hierarchy with the correct annotations to perform this unmarshalling but i would like to have a code like:
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "TEST")
#XmlAccessorType (XmlAccessType.FIELD)
public class Info {
// -> what annotation to put here?
private List<String> infos;
public List<String> getInfos() {
return infos;
}
}
And the main file:
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
public class UnmarshallingJAXB {
public static void main(String[] args) throws JAXBException {
JAXBContext jaxbContext = JAXBContext.newInstance(Info.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Info info = (Info) jaxbUnmarshaller.unmarshal(new File("test.xml"));
// should output foo.png and bar.png
info.getInfos().forEach(System.out::println);
}
}
Is there any way to do that?
Apologies for answering so late, but this is the first hit on Google if search for related problems so it might help anyway.
Yes, it is possible, using
#XmlElementWrapper
in combination
#XmlElement
See this example for more detailed info.
I have been working hard to make below program work, but there seems to be some serious flaw either in my code or with #XmlPath annotation.
XML that I am trying to parse:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<information>
<customer id="customer1">
<billingAddress id="address1">
<street id="street1">1 Billing Street</street>
<street id="street2">2 Billing Street</street>
</billingAddress>
</customer>
</information>
The Pojo that I am creating:
package parser;
import lombok.ToString;
import org.eclipse.persistence.oxm.annotations.XmlPath;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
#ToString
#XmlRootElement(name = "information")
#XmlAccessorType(XmlAccessType.FIELD)
public class Information {
#XmlPath("customer/#id")//-------------------------------------> (1)
private String customerId;
#XmlPath("customer[#id='customer1']/billingAddress/#id") //-----> (2)
private String billingAddressId;
}
How I am unmarshalling the xml:
import parser.Information;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.io.File;
public class Main {
public static void main(String[] args) throws JAXBException {
JAXBContext jaxbContext = org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(new Class[]{Information.class}, null);
Unmarshaller jaxbMarshaller = jaxbContext.createUnmarshaller();
Information information = (Information)jaxbMarshaller.unmarshal(new File("information.xml"));
System.out.println(information);
}
}
Output for the above is:
Information(customerId=null, billingAddressId=address1)
Clearly the output is incorrect. customerId is showing null instead of customer1. However, if I comment out the line (2) in pojo class then the customerId is getting correct value. Why is it so ? Why can't I read the correct customerId value in above program ?
Removing the [#id='customer1'] from the 2nd XmlPath does solve the issue for the provided code, even though I assume the real Information entity has much more fields which you address with XmlPath.
Why don't you use some classes to reflect the XML structure ... kinda like object-oriented? It'll simplify the JAXB modelling.
Required field is ignored and doesn't get generated.
For example for property a
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;
import com.wordnik.swagger.annotations.ApiModel;
import com.wordnik.swagger.annotations.ApiModelProperty;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#ApiModel( value = "aaa")
public class A implements IA
{
#ApiModelProperty( value = "bla", required = true )
#XmlElement(name="a")
private String a;
public String getC() { return "kkk";};
}
Seems that you should switch the order of annotations!
instead of
#ApiModelProperty( value = "bla", required = true )
#XmlElement(name="a")
private String a;
write
#XmlElement(name="a")
#ApiModelProperty( value = "bla", required = true )
private String a;
Seems like a bug to me. Hopefully would be fixed in newer versions
this is fixed in https://github.com/swagger-api/swagger-core/commit/8c24ab4863e9e7bcd8a98add848b31af81ef77f2 which will be released in 1.3.12
i'm trying to unmarshall an xml like this:
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:b2bHotelSOAP" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<ns1:getAvailableHotelResponse>
<return xsi:type="ns1:getAvailableHotelResponse">
<responseId xsi:type="xsd:integer">1</responseId>
<searchId xsi:type="xsd:string">HR-47754204</searchId>
<totalFound xsi:type="xsd:integer">20</totalFound>
<availableHotels SOAP-ENC:arrayType="ns1:hotel[20]" xsi:type="ns1:hotelArray">
...
</availableHotels>
</return>
</ns1:getAvailableHotelResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
i'm using that package-info.java to specify the namespace used into soap response:
#XmlSchema(
namespace="http://schemas.xmlsoap.org/soap/envelope/",
elementFormDefault=XmlNsForm.QUALIFIED,
xmlns={
#XmlNs(namespaceURI = "http://schemas.xmlsoap.org/soap/envelope/", prefix = "SOAP-ENV"),
#XmlNs(namespaceURI = "urn:b2bHotelSOAP", prefix = "ns1"),
#XmlNs(namespaceURI = "http://www.w3.org/2001/XMLSchema", prefix = "xsd"),
#XmlNs(namespaceURI = "http://www.w3.org/2001/XMLSchema-instance", prefix = "xsi"),
#XmlNs(namespaceURI = "http://schemas.xmlsoap.org/soap/encoding/", prefix = "SOAP-ENC")
}
)
#XmlAccessorType(XmlAccessType.FIELD)
package com.giove.viaggi.hsw.provider.hotelspro;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
what i need is to unmarshall that soap xml into this bean:
package myPackage;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement(name="Envelope")
public class MyBean {
#XmlPath("return/availableHotels/item")
private List<Hotel> hotels;
public List<Hotel> getHotels(){
return this.hotels==null?new ArrayList<Hotel>():this.hotels;
}
}
When i try to unmarshall it using jaxbUnmarshaller it gives me always null for the hotels attribute even if they are present into soap response.
Do i make any mistake?
Can please someone give me an help?
Thanks!
MyBean
Below is what the #XmlPath annotation on your MyBean class should look like. Some things to note:
Your domain class must be in the same package as the package-info class you want applied to it.
When you use #XmlPath you need to include each step in the path, you had left some out.
Namespace qualfifcation in the #XmlPath corresponds to the prefixes you have defined in the #XmlSchema annotation (see: http://blog.bdoughan.com/2010/09/xpath-based-mapping-geocode-example.html).
package com.giove.viaggi.hsw.provider.hotelspro;
import java.util.*;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement(name="Envelope")
public class MyBean {
#XmlPath("SOAP-ENV:Body/ns1:getAvailableHotelResponse/return/availableHotels/item")
private List<Hotel> hotels;
public List<Hotel> getHotels(){
return this.hotels==null?new ArrayList<Hotel>():this.hotels;
}
}
Note
Instead of mapping the MyBean class to the Envelope element I would map it to the local root return and pass it that element to unmarshal instead.
http://blog.bdoughan.com/2012/08/handle-middle-of-xml-document-with-jaxb.html
For some reason, all values of an element gets written twice.
My test case is very simple:
package test;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlAccessorType(XmlAccessType.NONE)
#XmlRootElement(name="root")
public class TestBean {
private String name = null;
#XmlElement(name="lastname")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Then I marshall the document to the filesystem into an XML:
TestBean object = new TestBean();
object.setName("abc ");
Class<?> clazz = object.getClass();
JAXBContext context = JAXBContext.newInstance(clazz);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE );
m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
m.marshal(object, new File("test.xml"));
And the resulting XML is:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<lastname>abc abc </lastname>
</root>
For simplicity I removed the package-info.java file with the namespace definitions.
The implementation I am using is org.eclipse.persistence.moxy 2.1.2:
the jaxb.properties file in the package folder contains this line:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Thanks for any hints.
This is a known MOXy issue that has been fixed in the EclipseLink 2.3.0 stream. An EclipseLink 2.3.0 download can be obtained here:
http://www.eclipse.org/eclipselink/downloads/nightly.php
The workaround for EclipseLink 2.1.2 is to use another access type, or to annotate the corresponding field with #XmlTransient:
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
#XmlAccessorType(XmlAccessType.NONE)
#XmlRootElement(name="root")
public class TestBean {
#XmlTransient
private String name = null;
#XmlElement(name="lastname")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
I tried your test and it gives the correct output for me:
<root>
<lastname>abc </lastname>
</root>
It could be the JAXB2 implementation (moxy in your case vs native JDK1.6 based JAXB2 for my test).