i need your help : please, please please.
I've a Xades-signed XML document that i receive as a byteArray : so i convert my byteArray to a String.
After, i try to unmarhall so that i obtain a Java Object mapped.
The result is that i get an instance of "MyJavaObj" with all informations but Xades-Signature. My signature is null in the Java Object while all other informations are well-mapped. The following is my java method. Please, help me to get the object signature in the instance of MyJavaObj.
<school>
<documentVersion>2.10</documentVersion>
<teacher>
.....
</teacher>
<student>
<name></name>
<age></age>
....
</student>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="xmldsig-2b72d2f4-4794-4a8b-8cbf-4c74d33629a7">
<ds:SignedInfo>
........
</ds:SignedInfo>
.......
</ds:Signature>
</school>
this is the method to convert
public static MyJavaObj unmarshallBinary(final byte[] pByteStr) {
try {
final String xmlFlow = new String(pByteStr, "UTF-8");
final StringBuffer xmlStr = new StringBuffer(xmlFlow);
// Unmarshalling with JAXB
final JAXBContext jaxbContext = JAXBContext.newInstance("generated.package");
// marshaller
final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
// Unmarshalling
final JAXBElement<MyJavaObj> root = unmarshaller.unmarshal(
new StreamSource(new StringReader(xmlStr.toString())), MyJavaObj.class);
return root.getValue();
} catch (final Throwable excep) {
excep.printStacktrace();
}
}
MyJavaObj result = unmarshallBinary(..a ByteArray..);
result.getDocumentVersion() : returns 2.10;
result.getStudent() : returns the students;
result.getSignature() : return NULL;
The file MyJavaObj.java is well annotated
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "My_Java_Obj", namespace = "urn:my_java_obj",
propOrder = {"documentVersion", "teacher", "student","signature"})
public class MyJavaObj {
#XmlElement(name = "documentVersion", required = true)
protected String documentVersion;
#XmlElement(name = "teacher", required = true)
protected Teacher teacher;
#XmlElement(name = "student", required = true)
protected Student student;
#XmlElement(name = "Signature")
protected Signature signature;
#XmlAttribute(name = "Id", required = true)
#XmlJavaTypeAdapter(CollapsedStringAdapter.class)
#XmlID
#XmlSchemaType(name = "ID")
protected String id;
.....
getters and setters
}
Thanks for any help.
The Signature element is in the http://www.w3.org/2000/09/xmldsig#" namespace so you need to include this in the #XmlElement for the signature field.
#XmlElement(name="Signature", namespace="http://www.w3.org/2000/09/xmldsig#")
protected Signature signature;
For More Information
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
my solution is bit different
i used uddi-ws. Maven dependency is here:
<!-- https://mvnrepository.com/artifact/org.apache.juddi/uddi-ws -->
<dependency>
<groupId>org.apache.juddi</groupId>
<artifactId>uddi-ws</artifactId>
<version>3.3.2</version>
</dependency>
In class:
//in my case, import org.w3.x2000.x09.xmldsig.SignatureType isn't working
import org.w3._2000._09.xmldsig_.SignatureType;
//Signature declaration
private SignatureType Signature;
//namespace is important part, without namespace, it returns null
#XmlElement(name = "Signature", namespace = "http://www.w3.org/2000/09/xmldsig#")
public SignatureType getSignature() {
return Signature;
}
More info:
https://www.codesynthesis.com/pipermail/xsd-users/2006-December/000674.html
Related
TL;DR: When I unmarshall from XML to POJO I only have the XmlAttributes well mapped, however all XmlElement are null.
Hi there!
I have the following problem. This class was generated with JAXB
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"activity"
})
#XmlRootElement(name = "activityDetails", namespace = "http://lorem.ipsum.com/")
public class ActivityDetails {
#XmlElement(required = true)
protected Activity activity;
#XmlAttribute(name = "schemaVersion", required = true)
protected float schemaVersion;
#XmlAttribute(name = "actionType")
protected ActionTypes actionType;
#XmlSchemaType(name = "dateTime")
protected XMLGregorianCalendar timestamp;
This is an example XML
<activityDetails
actionType="CREATE"
schemaVersion="2.0"
timestamp="2020-01-02T15:31:50.549Z"
xmlns="http://lorem.ipsum.com/">
<activity>
<activityId>
<start>2020-01-01T03:00:00Z</start>
<end>2020-01-02T02:59:00Z</end>
</activityId>
</activity>
</activityDetails>
But, when this code is executed (please don't judge me, it's legacy code):
Object xmlClass = Class.forName("com.lorem.ipsum." + className).getConstructor().newInstance();
final JAXBContext jaxbContext = JAXBContext.newInstance(xmlClass.getClass());
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Object object = unmarshaller.unmarshal(new StringReader(element));
The result "object" have all XmlAttribute well mapped, but no one of their XmlElement
PS: The namespace in the generated class was added manually, if I don't do that I have this exception:
javax.xml.bind.UnmarshalException: unexpected element (uri:"http://lorem.ipsum.com/", local:"activityDetails"). Expected elements are <{}activityDetails>
Thanks in advance.
UPDATED: If I set all #XmlElement the namespace property I finally map the elements, but I must intervene all the classes. Is there another way to achieve that without having to modify all the fields of all the classes?
I guess I am able to figure out the issue. This is happening because you have not provided any prefix to your namespace in XML. Following code would work for your provided sample XML:
XML:
<activityDetails
actionType="CREATE"
schemaVersion="2.0"
timestamp="2020-01-02T15:31:50.549Z"
xmlns:ns0="http://lorem.ipsum.com/">
<activity>
<activityId>
<start>2020-01-01T03:00:00Z</start>
<end>2020-01-02T02:59:00Z</end>
</activityId>
</activity>
</activityDetails>
ActivityDetails.class:
#XmlAccessorType(XmlAccessType.FIELD)
#Data
#XmlRootElement(name = "activityDetails", namespace = "http://lorem.ipsum.com/")
public class ActivityDetails {
private Activity activity;
#XmlAttribute
private float schemaVersion;
#XmlAttribute
private String actionType;
#XmlAttribute
private String timestamp;
}
Activity.class:
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class Activity {
private ActivityID activityId;
}
ActivityID.class:
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class ActivityID {
private String start;
private String end;
}
Main.class:
public class Main {
public static void main(String[] args) throws JAXBException, XMLStreamException {
final InputStream inputStream = Main.class.getClassLoader().getResourceAsStream("activity.xml");
final XMLStreamReader xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
final Unmarshaller unmarshaller = JAXBContext.newInstance(ActivityDetails.class).createUnmarshaller();
final ActivityDetails activityDetails = unmarshaller.unmarshal(xmlStreamReader, ActivityDetails.class).getValue();
System.out.println(activityDetails.toString());
Marshaller marshaller = JAXBContext.newInstance(ActivityDetails.class).createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(activityDetails, System.out);
}
}
Following is your output:
ActivityDetails(activity=Activity(activityId=ActivityID(start=2020-01-01T03:00:00Z, end=2020-01-02T02:59:00Z)), schemaVersion=2.0, actionType=CREATE, timestamp=2020-01-02T15:31:50.549Z)
<ns0:activityDetails xmlns:ns0="http://lorem.ipsum.com/" schemaVersion="2.0" actionType="CREATE" timestamp="2020-01-02T15:31:50.549Z">
<activity>
<activityId>
<start>2020-01-01T03:00:00Z</start>
<end>2020-01-02T02:59:00Z</end>
</activityId>
</activity>
</ns0:activityDetails>
Finally I found this solution: Instead of putting the namespace in each of the XMLElements I put the following package-info.java in the package of the generated classes.
#XmlSchema(
elementFormDefault=XmlNsForm.QUALIFIED,
namespace="http://lorem.ipsum.com/",
xmlns={#XmlNs(prefix="", namespaceURI="http://lorem.ipsum.com/")})
package com.lorem.ipsum.generated;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
I need to create a XML which matches this structure:
<OfferPackage Name="aaa">
<OfferPackage.Offers>
<OfferCollection Capacity="1">
<Offer Price="12.34"/>
<Offer Price="12.34"/>
</OfferCollection>
</OfferPackage.Offers>
</OfferPackage>
My problem is that I do not know how to achieve this here: <OfferPackage.Offers>. How I can get this "dot notation" with just annotations? All I got out looks like this:
<OfferPackage Name="aaa">
<OfferCollection Capacity="1">
<Offer Price="12.34"/>
<Offer Price="12.34"/>
</OfferCollection>
</OfferPackage>
This is my current code:
#XmlRootElement(name = "OfferPackage")
#XmlAccessorType(XmlAccessType.FIELD)
public class OfferPackage {
#XmlAttribute(name = "Name")
private String name = null;
#XmlElement( name = "OfferCollection")
private List<OfferCollection> offers = null;
#SneakyThrows
public String toString() {
var sw = new StringWriter();
var marshaller = JAXBContext
.newInstance(OfferPackage.class)
.createMarshaller();
marshaller.setProperty(JAXB_FRAGMENT, true);
marshaller.marshal(this, sw);
return sw.toString();
}
}
#XmlRootElement(name = "Offer")
#XmlAccessorType(XmlAccessType.FIELD)
public class OfferCollection {
#XmlAttribute(name = "Capacity")
private Integer capacity = null;
#XmlElement(name = "Offer")
private List<Offer> offer = null;
}
You can achieve the desired behavior using the #XmlElementWrapper annotation:
Generates a wrapper element around XML representation. This is primarily intended to be used to produce a wrapper XML element around collections.
In your case, it will look similar to this:
#XmlRootElement(name = "OfferPackage")
#XmlAccessorType(XmlAccessType.FIELD)
public class OfferPackage {
#XmlAttribute(name = "Name")
private String name = null;
#XmlElementWrapper(name="OfferPackage.Offers")
#XmlElement( name = "OfferCollection")
private List<OfferCollection> offers = null;
#SneakyThrows
public String toString() {
var sw = new StringWriter();
var marshaller = JAXBContext
.newInstance(OfferPackage.class)
.createMarshaller();
marshaller.setProperty(JAXB_FRAGMENT, true);
marshaller.marshal(this, sw);
return sw.toString();
}
}
Other possibility will be to define an intermediate class, OfferPackageOffers to wrap the OfferCollection List::
#XmlRootElement(name = "OfferPackage.Offers")
#XmlAccessorType(XmlAccessType.FIELD)
public class OfferPackageOffers {
#XmlElement( name = "OfferCollection")
private List<OfferCollection> offers = null;
//...
}
And use the new class in OfferPackage instead of the mentioned OfferCollection List:
#XmlRootElement(name = "OfferPackage")
#XmlAccessorType(XmlAccessType.FIELD)
public class OfferPackage {
#XmlAttribute(name = "Name")
private String name = null;
#XmlElement( name = "OfferPackage.Offers")
private OfferPackageOffers offers = null;
//...
}
I have the following JAXB entity:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = EntityConstants.PARTNER)
public class FilePartner
{
#XmlAttribute(name = EntityConstants.IDENTIFIER, required = true)
private String identifier;
#XmlElement(name = EntityConstants.NAME)
private String name;
#XmlElement(name = EntityConstants.ROOT_PATH)
private String rootPath;
...
}
which serialized into a similar structure:
<file-partner identifier="foo">
<name>bar</name>
<root-path>path123</root-path>
...
</file-partner>
I also have an entity which represents a list of partners:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = EntityConstants.PARTNERS)
public class FilePartnerList
{
#XmlElement(name = EntityConstants.PARTNER)
private List<FilePartner> partners = new ArrayList<FilePartner>();
public List<FilePartner> getPartners()
{
return partners;
}
public void addPartners(List<FilePartner> partners)
{
this.partners.addAll(partners);
}
}
which serializes into:
<partners>
<file-partner identifier="foo">
...
</file-partner>
<file-partner identifier="foo2">
...
</file-partner>
...
</partners>
I am looking for a way to force the jaxb unmarshaller to deserialize XMLs in the form of
<file-partner identifier="foo">
<name>bar</name>
<root-path>path123</root-path>
...
</file-partner>
into FilePartnerList instances with list size of 1, i.e:
JAXBContext context = JAXBContext.newInstance(FilePartner.class, FilePartnerList.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
InputStream inputStream = getResourceAsStream(filePartnerAsXml);
FilePartnerList partnerList = (FilePartnerList) unmarshaller.unmarshal(inputStream); // This SHOULD be unmarshalled to FilePartnerList instead of FilePartner
assertTrue(partnerList.getPartners().getSize().equals(1));
How do I achieve that?
private List<FilePartner> partners = new ArrayList<FilePartner>(**1**);
That way you'll get a fixed size input array....
But I'm sure that you will want to get the XSD of that model with the 'maxocurrs=1' so you will end modifying the XSD manually.
Anyway: why don't you, if the list size must be fixed to '1', simply set it as a simple node with a single child? Something like this (untested):
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = EntityConstants.PARTNERS)
public class FilePartnerList
{
#XmlElement(name = EntityConstants.PARTNER)
private FilePartner partners;
public FilePartner getFilePartner()
{
return partner;
}
public void setPartner(FilePartner partner)
{
this.partner = partner;
}
}
This way you will have one and only one partner per parnets-list.
The XML that fullfits the XSD of your service a text and in that text is indistinguible a list with max size 1 and a node.
I have just started to learn how to make a java object from a XML. However, now I have a tricky input and I don't really know how to solve it.
This is the input:
<?xml version="1.0" encoding="UTF-8"?>
<return>
<productChange cd_product="711" ds_product="MBL40337 I151 BLACK P" cd_species="UN" cd_tipi="61062000" cd_cst="5" qt_weight="" cd_nbm="" dt="2016-05-04 11:47:36">
<productvalue cd_company="1" cd_product="711" tp_value="P" cd_value="1" vl_product="61.39">
<tipovaluePrd tp_value="P" cd_value="1" ds_value="SALE" cd_corrency="1" />
</productvalue>
<productvalue cd_company="1" cd_product="711" tp_value="P" cd_value="4" vl_product="129.8">
<tipovaluePrd tp_value="P" cd_value="4" ds_value="SALE STORE" cd_corrency="1" />
</productvalue>
<productvalue cd_company="1" cd_product="711" tp_value="P" cd_value="5" vl_product="64.9">
<tipovaluePrd tp_value="P" cd_value="5" ds_value="SALE AT" cd_corrency="1" />
</productvalue>
<productvalue cd_company="1" cd_product="711" tp_value="P" cd_value="8" vl_product="122.78">
<tipovaluePrd tp_value="P" cd_value="8" ds_value="SALE FQ" cd_corrency="1" />
</productvalue>
</productChange>
</return>
To consume this xml with JaxB (XML provided by a third party company) I have built the following classes:
#XmlAccessorType(XmlAccessType.FIELD)
public class ProductUpdateResponse {
#XmlAttribute(name = "cd_product")
private Integer productCode;
#XmlAttribute(name = "ds_product")
private String productDescription;
#XmlAttribute(name = "cd_species")
private String productSpecie;
#XmlAttribute(name = "cd_tipi")
private Integer productTIPI;
#XmlAttribute(name = "cd_cst")
private Integer productCST;
#XmlAttribute(name = "qt_weight")
private String productWeight;
#XmlAttribute(name = "cd_nbm")
private String productNBM;
#XmlAttribute(name = "dt")
private String productDate;
#XmlElement(name = "productvalue")
private ProductValueType productValue;
// getters and setters
}
#XmlAccessorType(XmlAccessType.FIELD)
public class ProductValue {
#XmlAttribute(name = "cd_product")
private Integer productCode;
#XmlAttribute(name = "cd_company")
private Integer companyCode;
#XmlAttribute(name = "tp_value")
private String valueType;
#XmlAttribute(name = "cd_value")
private Integer valueCode;
#XmlAttribute(name = "vl_product")
private BigDecimal productValue;
#XmlElement(name = "tipovaluePrd")
private ProductValueType productValueType;
//getters and seters
}
#XmlAccessorType(XmlAccessType.FIELD)
public class ProductValueType {
#XmlAttribute(name = "tp_value")
private String valueType;
#XmlAttribute(name = "cd_value")
private String valueCode;
#XmlAttribute(name = "ds_value")
private String valueDescription;
#XmlAttribute(name = "cd_corrency")
private Integer valueCurrency;
//getters and seters
}
However, the main information, for me, is comming as null (productvalue) I wonder if it is because there are four tags productvalue in the xml (I just need the one whose tipovaluePrd.cd_value is 4 ).
Below is the method I'm using to parse the XML:
private ProductUpdateResponse buildResponse(String rawResponse, Class<T> responseClass) {
JAXBContext jaxbContext = null;
try {
jaxbContext = JAXBContext.newInstance(responseClass);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
StringReader reader = new StringReader(rawResponse);
return (ProductUpdateResponse) unmarshaller.unmarshal(reader);
} catch (JAXBException | ClassCastException e) {
return null;
}
}
So, I wonder if there is a way to read specifically the value I want (productvalue element that has tipovaluePrd.cd_value = 4) and how could I do that. If there isn't, how should I build my class so I can read properly everything?
Changing the input is not an option here...
Thanks in advance for any help.
I'm actually surprised you're getting a result from JAXB with your current setup.
You lack a class representing your root element :
#XmlRootElement(name="return")
#XmlAccessorType(XmlAccessType.FIELD)
public class Return {
#XmlElement(name="productchange")
private ProductUpdateResponse response;
//getters and setters
}
Also, in your ProductUpdateResponse class, you should change :
#XmlElement(name = "productvalue")
private ProductValueType productValue;
by
#XmlElement(name = "productvalue")
private List<ProductValue> productValues;
Finally, in your buildResponse method, make sure the responseClass argument is Return.class.
With this, you should have a list with all your productvalue element. You just have to get the productvalue your interested in from it.
If you only want to get the element you're interested with :
As swasa suggested it, you can use the javax.xml.xpath to make an Xpath request on your XML.
If you're willing to change your JAXB Implementation : EclipseLink JAXB Implementation implements an #XmlPath annotation that allows you to bind objects according to an XPath request :
#XmlPath(name = "productvalue/tipovaluePrd[#cd_value=4]")
private ProductValueType productValueType;
I'm getting null value when unmarshelling the xml file to java class. But the xml file as values corresponding to the its attributes. Is there any mistake in my pojo class or unmarshelling?
Please help
This is my pojo
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "")
#XmlRootElement(name = "CardUpdateResponse",namespace="http://www.samople.com/Prepaid")
public class FVCardUpdateResponse {
#XmlElement(name = "AccountNumber")
private String AccountNumber;
#XmlElement(name = "ResCode")
private String ResCode;
#XmlElement(name = "ResErrorCode")
private String ResErrorCode;
#XmlElement(name = "ResErrorMsg")
private String ResErrorMsg;
//Setters and Getters
}
This is my xml file
<?xml version="1.0" encoding="UTF-8"?>
<CardUpdateResponse xmlns="http://www.samople.com/Prepaid">
<CARDUPDATE_RET>
<ResErrorMsg>ID Issue Date must be equal or less than present date</ResErrorMsg>
<ResErrorCode>ErrIsud01</ResErrorCode>
<ResCode>0</ResCode>
<ACCOUNTNUMBER>2000000003918246</ACCOUNTNUMBER>
</CARDUPDATE_RET>
</CardUpdateResponse>
this is code for unmarshelling
public class XmlUnmarshelling {
public void unmarshell()
{
try
{
System.out.println("xml unmarshelling class");
File file = new File("D:/var/lib/tomcat7/webapps/tmpFiles/1.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(FVCardUpdateResponse.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
FVCardUpdateResponse CARDUPDATE_ret = (FVCardUpdateResponse) jaxbUnmarshaller.unmarshal(file);
System.out.println("xml unmarshelled = "+CARDUPDATE_ret.getResErrorMsg());//Getting null value as response.
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
Your POJO doesn't have the same structure as your XML. CardUpdateResponse doesn't directly contain the properties in your POJO, it contains CARDUPDATE_RET element which contains the properties.
You could modify your POJO like this to match the XML:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "CardUpdateResponse", namespace="http://www.samople.com/Prepaid")
public static class CardUpdateResponseWrapper {
#XmlElement(name="CARDUPDATE_RET")
private FVCardUpdateResponse response;
// Getter and setter for response
public static class FVCardUpdateResponse {
#XmlElement(name = "AccountNumber")
private String AccountNumber;
#XmlElement(name = "ResCode")
private String ResCode;
#XmlElement(name = "ResErrorCode")
private String ResErrorCode;
#XmlElement(name = "ResErrorMsg")
private String ResErrorMsg;
// Getters and setters
}
}
Now the CardUpdateResponseWrapper class will represent your root XML element and it will have instance of FVCardUpdateResponse which will represent the CARDUPDATE_RET XML element.
Do unmarshall it, just call:
File file = new File("D:/var/lib/tomcat7/webapps/tmpFiles/1.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(CardUpdateResponseWrapper.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
CardUpdateResponseWrapper wrapper = (CardUpdateResponseWrapper) jaxbUnmarshaller.unmarshal(file);
System.out.println(wrapper.getResponse().getResErrorMsg());
I think that the issue is a combination of two problems, one what Bohuslav is saying, the other you need to repeat your namespace on every XmlElement annotation, e.g.
#XmlElement(name = "ResCode", namespace="http://www.samople.com/Prepaid")
and one particular issue, you need to match the cases as well so the name for AccountNumber should be capitalized ACCOUNTNUMBER