XML Namespace prefix d2lm on d2LogicalModel is not defined using jaxb - java

I need to put a xmlns in each SOAP component and also y the data model included in the SOAP body, but when I simply include the ns in the XmlElement name it does not work properly, thanks.
SOAP Body:
package soap;
import eu.datex2.schema._2_0._2_3.D2LogicalModel;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
#XmlType(name = "body", propOrder = {
"soapBody"
})
#XmlAccessorType(XmlAccessType.FIELD)
public class Body {
#XmlElement(name="d2lm:d2LogicalModel")
private D2LogicalModel soapBody;
public Body() {
this.soapBody = new D2LogicalModel();
}
public D2LogicalModel getSoapBody() {
return this.soapBody;
}
public void setSoapBody(D2LogicalModel soapBody) {
this.soapBody = soapBody;
}
}
SOAP header:
package soap;
import eu.datex2.schema._2_0._2_3.D2LogicalModel;
import javax.xml.bind.annotation.*;
#XmlType(name = "envelope", propOrder = {
"soapEnv",
"soapHeader",
"body"
})
#XmlRootElement(name = "soapenv:Envelope")
#XmlAccessorType(XmlAccessType.FIELD)
public class Envelope {
#XmlAttribute(name="xmlns:soapenv")
private String soapEnvEncodingStyle;
#XmlAttribute(name="xmlns:env")
private String soapEnv;
#XmlElement(name="soapenv:Header")
private String soapHeader;
#XmlAttribute(name="xmlns:xdt")
private String soapXdt;
#XmlAttribute(name="xmlns:xsd")
private String soapXsd;
#XmlAttribute(name="env:schemaLocation")
private String schemaLocation;
#XmlElement(name="soapenv:Body")
private Body body;
public Envelope(){
this.soapEnvEncodingStyle = "http://schemas/xmlsoap.org/soap/envelope/";
this.soapEnv = "http://www.w3.org/2001/XMLSchema-instance";
this.soapXdt = "http://www.w3.org/2004/07/xpath-datatypes";
this.soapXsd = "http://www.w3.org/2001/XMLSchema";
this.schemaLocation = "http://schemas/xmlsoap.org/soap/envelope/";
this.soapHeader = new String();
this.body = new Body();
}
public Body getSoapBody() {
return this.body;
}
public void setBody(Body soapBody) {
this.body = soapBody;
}
}

If I delete the prefix d2lm it works, thanks

Related

Consume SOAP Service from SpringBoot - #RequestBody getting null values

I am getting null value for empID in RequestControllers RequestBody MyReq request. When I called Rest Service using below JSON Request.
{
"EmpID": [
"1111","1234"
]
}
This is my Controller
#SpringBootApplication
#RestController
public class MessageProcessorApplication {
#Autowired
private SoapClient client;
#RequestMapping(value = "/getIdDetails", method = RequestMethod.POST)
public MyRsp invokeSoapClient(#RequestBody MyReq request)
{
return client.getIdDetails(request);
}
}
My SoapClient class
#Service
public class SoapClient {
#Autowired
private Jaxb2Marshaller marshaller;
private WebServiceTemplate template;
public MyRsp getIdDetails(MyReq request)
{
template = new WebServiceTemplate(marshaller);
MyRsp response = (MyRsp) template.marshalSendAndReceive("http://localhost:8080/ws",request);
return response;
}
}
jaxb generated MyReq and EmpID classes from SOAP Service WSDL
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"empID"
})
#XmlRootElement(name = "MyReq")
public class MyReq
extends BaseReq
{
#XmlElement(name = "EmpID", required = true)
protected List<EmpID> empID;
public void setEmpID(List<EmpID> empID) {
this.empID = empID;
}
public List<EmpID> getEmpID() {
if (empID == null) {
empID = new ArrayList<EmpID>();
}
return this.empID;
}
}
}
generated EmpID class
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"value"
})
#XmlRootElement(name = "EmpID")
public class EmpID {
#XmlValue
protected String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
I have tried with empID also in JSON Request. Still null values I am getting.
You may be running into this problem. You also need to pass the value of EmpID in the constructor.
I can get your example to work if I change your generated classes to...
MyReq.java
package com.example.demo;
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 java.util.List;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "MyReq")
public class MyReq
{
#XmlElement(required = true)
protected List<EmpID> empIds;
public List<EmpID> getEmpIds() {
return empIds;
}
public void setEmpIds(List<EmpID> empIds) {
this.empIds = empIds;
}
}
EmpID.java
package com.example.demo;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlValue;
#XmlAccessorType(XmlAccessType.FIELD)
public class EmpID {
public EmpID(String value) {
this.value = value;
}
#XmlValue
protected String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
You would then need to post your json as...
{
"empIds": ["1111","1234"]
}
try with this json request.
{
"empID": [
{
"value": "111"
},
{
"value": "222"
}
]
}

Parsing XML Failed

I get the following response XML String after calling a SOAP web service. How can i parse the response back to Java entity so that i can handle the ErrMsg and Status accordingly? I tried with the below code, but keep getting error
Exception in thread "main" javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"NewDataSet"). Expected elements are <{TransactionalSubmissionsSvcs}NewDataSet>
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:726)
Sample Response in String
<NewDataSet>
<SubmissionResult>
<Status>200</Status>
<RefNo>363180319bigKj83i</RefNo>
<ErrMsg>Successful</ErrMsg>
</SubmissionResult>
</NewDataSet>
Sample Client XML Parser
JAXBContext jaxbContext = JAXBContext.newInstance(NewDataSet.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
StringReader reader = new StringReader("Sample Response in String above");
NewDataSet newDataSet = (NewDataSet) jaxbUnmarshaller.unmarshal(reader);
System.out.println(newDataSet.getSubmissionResult());
NewDataSet.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;
import javax.xml.bind.annotation.XmlType;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"submissionResult"
})
#XmlRootElement(name = "NewDataSet")
public class NewDataSet {
#XmlElement(name = "SubmissionResult", required = true)
protected NewDataSet.SubmissionResult submissionResult;
public NewDataSet.SubmissionResult getSubmissionResult() {
return submissionResult;
}
public void setSubmissionResult(NewDataSet.SubmissionResult value) {
this.submissionResult = value;
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"status",
"refNo",
"errMsg"
})
public static class SubmissionResult {
#XmlElement(name = "Status")
protected short status;
#XmlElement(name = "RefNo", required = true)
protected String refNo;
#XmlElement(name = "ErrMsg", required = true)
protected String errMsg;
public short getStatus() {
return status;
}
public void setStatus(short value) {
this.status = value;
}
public String getRefNo() {
return refNo;
}
public void setRefNo(String value) {
this.refNo = value;
}
public String getErrMsg() {
return errMsg;
}
public void setErrMsg(String value) {
this.errMsg = value;
}
}
}
Note: If possible i prefer to use standard java library or external library that is being maintained regularly and up to date.
It looks like you have many NewDataSet classes in your POJO model. Check this line of code JAXBContext.newInstance(NewDataSet.class) and check import whether you imported correct one because exception says that marshaller expects TransactionalSubmissionsSvcs.NewDataSet.
Before edit
You did not mention what the tool do you use. In case it is Jackson you can parse XML payload as below:
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import java.io.File;
import java.nio.file.Files;
public class XmlMapperApp {
public static void main(String[] args) throws Exception {
String xml = "your xml";
parse(xml);
}
public static void parse(String xml) throws Exception {
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.enable(SerializationFeature.INDENT_OUTPUT);
JsonNode root = xmlMapper.readTree(xml);
JsonNode result = root.at("/SendWithXMLResult");
JsonNode jsonNode = xmlMapper.readTree(result.asText());
JsonNode submissionResult = jsonNode.at("/SubmissionResult");
System.out.println(submissionResult.get("Status"));
System.out.println(submissionResult.get("ErrMsg"));
System.out.println(submissionResult.get("RefNo"));
}
}
If you have prepared POJO model you can deserialise XML directly to it using readValue method.
Found the reason, it was resolved by removing the namespace = "TransactionalSubmissionsSvcs"
#javax.xml.bind.annotation.XmlSchema(namespace = "TransactionalSubmissionsSvcs",elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.mailadapter;
to become
#javax.xml.bind.annotation.XmlSchema(elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.mailadapter;

Binding a child object of an XmlElement list to a Java object using Jackson XmlMapper

Given the following xml:
<?xml version="1.0" encoding="utf-8"?>
<live_schedules>
<title>This Schedule</title>
<date>20190328</date>
<link>/v2/schedule</link>
<id>schedule</id>
<updated>2019-03-28T21:51:41+0</updated>
<schedule>
<sport id="1" name="Football" link="/v2/sport/1">
<league id="100" name="Alliance of American Football" link="/v2/league/100" />
<league id="101" name="Alliance of American Football" link="/v2/league/101" />
</sport>
</schedule>
</live_schedules>
And also given the following classes:
LiveScheduleDto.java
package com.stackoverflow.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#Data
#AllArgsConstructor
#XmlRootElement(name = "live_schedule")
#XmlAccessorType(XmlAccessType.FIELD)
public class LiveScheduleWrapper {
#XmlElement(name = "title")
private String title;
#XmlElement(name = "date")
private String date;
#XmlElement(name = "link")
private String link;
#XmlElement(name = "id")
private String id;
#XmlElement(name = "updated")
private String updatedDate;
#XmlElement(name = "schedule")
private ScheduleDto schedule;
}
ScheduleDto.java
package com.stackoverflow.dto;
import lombok.AllArgsConstructor;
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 java.util.List;
#AllArgsConstructor
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "schedule")
class ScheduleDto {
#XmlElement(name = "sport")
List<SportDto> sports;
}
SportDto.java
package com.stackoverflow.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import javax.xml.bind.annotation.*;
import java.util.List;
#Data
#AllArgsConstructor
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "sport")
public class SportDto {
#XmlAttribute(name = "id")
Integer id;
#XmlAttribute(name = "name")
String name;
#XmlAttribute(name = "link")
String link;
#XmlElementWrapper(name = "league")
List<LeagueDto> league;
}
LeagueDto.java
package com.stackoverflow.dto;
import lombok.AllArgsConstructor;
import javax.xml.bind.annotation.*;
#AllArgsConstructor
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "league")
public class LeagueDto {
#XmlAttribute(name = "id")
String id;
#XmlAttribute(name = "name")
String name;
#XmlAttribute(name = "link")
String link;
}
The adaptor that performs the mapping:
package com.stackoverflow.adaptors;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
import com.stackoverflow.dto.LiveScheduleWrapper;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import java.io.IOException;
public class ScheduleAdaptor {
private final HttpClient httpClient;
private final HttpGet httpGet;
public ScheduleAdaptor(HttpClient httpClient, HttpGet httpGet) {
this.httpClient = httpClient;
this.httpGet = httpGet;
}
public HttpApiResponse<LiveScheduleWrapper> retrieveSchedule() {
try {
HttpResponse response = httpClient.execute(httpGet);
XmlMapper mapper = new XmlMapper();
JaxbAnnotationModule module = new JaxbAnnotationModule();
mapper.registerModule(module);
LiveScheduleWrapper schedule =
mapper.readValue(response.getEntity().getContent(), LiveScheduleWrapper.class);
return new HttpApiResponse(response.getStatusLine().getStatusCode(), schedule);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
I am seeing when I run this through a parser that it is binding the SportDto to the LeagueDto because I've defined the <sport> element as a List. This isn't what I expected. Instead I expected that it would bind the Sport XmlElement to the SportDto object then the League to the nested League object as I've defined in my example.
What's the easiest way to correctly bind the <sport> xml element list to SportDto and the <league> xml element list to the LeagueDto?
I should make it clear I'm using Jacksons XmlMapper not JAXBContext
I managed to fix it. My issue was because I used the Jackson XmlMapper which isn't as full featured as the JAXBContext library...
I replaced my retrieveSchedule function with the following:
public HttpApiResponse<LiveScheduleWrapper> retrieveSchedule() {
try {
HttpResponse response = httpClient.execute(httpGet);
JAXBContext jc = JAXBContext.newInstance(LiveScheduleWrapper.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
LiveScheduleWrapper schedule = (LiveScheduleWrapper) unmarshaller.unmarshal(response.getEntity().getContent());
return new HttpApiResponse(response.getStatusLine().getStatusCode(), schedule);
} catch (JAXBException | IOException e) {
e.printStackTrace();
}
return null;
}
This solved my issue because JAXBContext correctly recognises JAXB annotations over XmlMapper.

How to avoid root element annotation while marshalling in JAXB?

I want to store my object data to XML. Below code spinets will show the example of model class.
Class Model
{
#XmlElement
private int id;
#XmlElement
Private string name;
}
I will have multiple model objects which will be stored in some list as below
#XmlRootElement
Class ModelWrapper
{
#XmlElement
#XmlJavaTypeAdapter(value = ListAdapter.class, type = List.class)
List<model> list;
public setlist(List<model>list)
{
//setting list
}
public List<model> getlist()
{
return list
}
}
Now if I marshall this using JAXB, something like this will be produced:
<Modelwrapper>
<List>
......
......
</List>
</Modelwrapper>
I want to avoid one of the root may be list or Modelwrapper.
Is there any way to do it?
In this way your xml will be
<ModelWrapper>
<model>
......
</model>
<model>
......
</model>
</ModelWrapper>
ModelWrapper.java
#XmlRootElement
public class ModelWrapper {
#XmlElement(name = "model")
protected List<Model> list;
Test
ModelWrapper.java
import java.util.List;
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.XmlType;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "ModelWrapper", propOrder = {
"list"
})
public class ModelWrapper {
#XmlElement(name = "model")
private List<Model> list;
public List<Model> getList() {
return list;
}
public void setList(List<Model> list) {
this.list = list;
}
}
Model.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;
import javax.xml.bind.annotation.XmlType;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Model", propOrder = {
"id","name"
})
public class Model {
#XmlElement
private int id;
#XmlElement
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Main.java
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
public class Main {
public static void main(String[] args) throws JAXBException {
JAXBContext jc = JAXBContext.newInstance(ModelWrapper.class);
ModelWrapper mw = new ModelWrapper();
List<Model> list = new ArrayList<Model>();
Model m = new Model();
m.setId(1);
m.setName("model1");
list.add(m);
m = new Model();
m.setId(1);
m.setName("model2");
list.add(m);
mw.setList(list);
Marshaller mar = jc.createMarshaller();
mar.marshal(mw, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<modelWrapper>
<model>
<id>1</id>
<name>model1</name>
</model>
<model>
<id>1</id>
<name>model2</name>
</model>
</modelWrapper>

Make custom xml from javabean

I wants to make xml from javabean like below:
<tag2>message</tag2>
<tag3>message</tag3>
<tag4 id='UNIQUE MT ID 1'>MOBILE No.</tag4>
I tried below code in javabean:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "name", propOrder = {"tag2", "tag3", "tag4"})
public class newBean {
#XmlElement(required = true)
private List<String> tag2;
#XmlElement(required = true)
private List<String> tag3;
#XmlElement(required = true)
private List<String> tag4;
#XmlPath("tag4/#id")
private List<String> id;
public List<String> getTag2() {
return tag2;
}
public void setTag2(List<String> tag2) {
this.tag2 = tag2;
}
public List<String> gettag4() {
return tag4;
}
public void settag4(List<String> tag4) {
this.tag4 = tag4;
}
public List<String> getId() {
return id;
}
public void setId(List<String> identifier) {
this.id = identifier;
}
public List<String> gettag3() {
return tag3;
}
public void settag3(List<String> tag3) {
this.tag3 = tag3;
}
}
I am getting below error:
Errorcom.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
Property id is present but not specified in #XmlType.propOrder
this problem is related to the following location:
at private java.util.List model.newBean.id
at model.newBean
Please help me.I am using #XmlPath tag and generating error.I searched alot and found that #XmlPath usage is same as above i used but still getting error.
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
About #XmlPath
#XmlPath is a EclipseLink JAXB (MOXy) extension and requires that you are using MOXy as your JAXB provider:
http://blog.bdoughan.com/2010/07/xpath-based-mapping.html
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html
Valid Use Case #1
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "name", propOrder = { "tag4", "id" })
public class newBean {
#XmlElement(required=true)
String tag4;
#XmlPath("tag4/#id")
String id;
}
Valid Use Case #2
import java.util.List;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "name", propOrder = { "tag4", "id" })
public class newBean {
#XmlPath("tag4/#id")
List<String> id;
}
Invalid Use Case
import java.util.List;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "name", propOrder = { "tag4", "id" })
public class newBean {
#XmlElement(required=true)
List<String> tag4;
#XmlPath("tag4/#id")
List<String> id;
}
Mapping Your Use Case
You could introduce an object that corresponds to the tag4 element that has two properties corresponding to the id attribute and text. This would work with any JAXB (JSR-222) implementation.
newBean
import java.util.List;
import javax.xml.bind.annotation.*;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "name", propOrder = { "tag4", "id" })
public class newBean {
List<Tag4> tag4;
}
Tag4
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
public class Tag4 {
#XmlAttribute
private String id;
#XmlValue
private String value;
}
For More Information
http://blog.bdoughan.com/2011/06/jaxb-and-complex-types-with-simple.html

Categories

Resources