Consume SOAP Service from SpringBoot - #RequestBody getting null values - java

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"
}
]
}

Related

Parsing JSON and Converting in List Of Object

I have a json response received from API Call the sample response is something like this
{
"meta": {
"code": "200"
},
"data": [
{
"Id": 44,
"Name": "Malgudi ABC"
},
{
"Id": 45,
"Name": "Malgudi, DEF"
}
]
}
I am trying to make List of Object from it, the code that i've written for this is
private static List<TPDetails> getListOfTpDetails(ResponseEntity<?> responseEntity){
ObjectMapper objectMapper = new ObjectMapper();
List<TPDetails> tpDetailsList = objectMapper.convertValue(responseEntity.getBody().getClass(), new TypeReference<TPDetails>(){});
return tpDetailsList;
}
Where TPDetails Object is Like this
public class TPDetails {
int Id;
String Name;
}
the code which i have used is resulting in
java.lang.IllegalArgumentException: Unrecognized field "meta" (class com.sbo.abc.model.TPDetails), not marked as ignorable (2 known properties: "Id", "Name"])
at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: com.sbo.abc.model.TPDetails["meta"])
I want to convert the Above JSON response in List
List<TPDetails> abc = [
{"Id": 44, "Name": "Malgudi ABC"},
{"Id": 45,"Name": "Malgudi DEF"}
]
Any help would be highly appreciable.Thanks well in advance
Create 2 more classes like
public class Temp {
Meta meta;
List<TPDetails> data;
}
public class Meta {
String code;
}
and now convert this json to Temp class.
Temp temp = objectMapper.convertValue(responseEntity.getBody().getClass(), new TypeReference<Temp>(){});
UPDATED :
Make sure responseEntity.getBody() return the exact Json String which you mentioned above.
Temp temp = objectMapper.readValue(responseEntity.getBody(), new TypeReference<Temp>(){});
The format of your java class does not reflect the json you are parsing. I think it should be:
class Response {
Meta meta;
List<TPDetails> data;
}
class Meta {
String code;
}
You should then pass Response to your TypeReference: new TypeReference<Response>(){}
If you don't care about the meta field, you can add #JsonIgnoreProperties
to your response class and get rid of the Meta class and field.
Create/update following class, I am storing JSON file, since do not have service, but should be fine and Able to parse it and read it from the following model.
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import java.util.List;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"meta",
"data"
})
public class OuterPoJo {
#JsonProperty("meta")
private Meta meta;
#JsonProperty("data")
private List<TPDetails> data = null;
#JsonProperty("meta")
public Meta getMeta() {
return meta;
}
#JsonProperty("meta")
public void setMeta(Meta meta) {
this.meta = meta;
}
#JsonProperty("data")
public List<TPDetails> getData() {
return data;
}
#JsonProperty("data")
public void setData(List<TPDetails> data) {
this.data = data;
}
}
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"code"
})
public class Meta {
#JsonProperty("code")
private String code;
#JsonProperty("code")
public String getCode() {
return code;
}
#JsonProperty("code")
public void setCode(String code) {
this.code = code;
}
}
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"Id",
"Name"
})
public class TPDetails {
#JsonProperty("Id")
private Integer id;
#JsonProperty("Name")
private String name;
#JsonProperty("Id")
public Integer getId() {
return id;
}
#JsonProperty("Id")
public void setId(Integer id) {
this.id = id;
}
#JsonProperty("Name")
public String getName() {
return name;
}
#JsonProperty("Name")
public void setName(String name) {
this.name = name;
}
}
import java.io.File;
public class App {
public static void main(String[] args) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
OuterPoJo myPoJo = objectMapper.readValue(
new File("file.json"),
OuterPoJo.class);
for (TPDetails item : myPoJo.getData()) {
System.out.println(item.getId() + ":" + item.getName());
}
}
}
output:
44:Malgudi ABC
45:Malgudi, DEF

unmarshaling always shows 0 and null

I think the best way is to copy my code so you can understand it.
Here are my POJO classes:
import javax.xml.bind.annotation.XmlAttribute;
public class Product {
private String name;
public Product() {
}
public Product(String name) {
this.name = name;
}
#XmlAttribute(name = "productName")
public String getProduct() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name="ShoppingCart")
public class Cart {
private List<Product> productList = new ArrayList<>();
private long CartIdentifier;
public Cart() {
}
public Cart(long id) {
this.CartIdentifier=id;
}
#XmlAttribute(name="CartIdentifier")
public long getId() {
return CartIdentifier;
}
public void setType(long id) {
this.CartIdentifier=id;
}
public Cart(List<Product> list) {
this.productList = list;
}
public void addElement(Product element) {
this.productList.add(element);
}
#XmlElement(name = "CurrentProducts")
public List<Product> getCart() {
return this.productList;
}
public void setCart(List<Product> cart) {
this.productList = cart;
}
}
import java.util.ArrayList;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "CashRegister")
public class Register {
#XmlElement(name = "ShoppingCart")
private ArrayList<Cart> listCart;
long CartIdentifier;
public Register() {
}
public Register(long id) {
this.CartIdentifier=id;
}
public long getId() {
return CartIdentifier;
}
public void addElementforBonus(Cart element) {
listCart.add(element);
}
public void setType(long id) {
this. CartIdentifier=id;
}
public void setList(ArrayList<Cart> list) {
this.listCart = list;
}
public ArrayList<Cart> getCartList() {
return listCart;
}
}
So those are my POJO classes and in main they create perfect XML, but when it comes to converting from XML to normal output something goes wrong. Can someone tell me where am I making mistake and why is my output than alway 0 and null?
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class Main {
public static void main(String[] args) throws JAXBException, IOException {
ArrayList<Cart> list = new ArrayList<Cart>();
Register store = new Register(1);
store.setType(1);
store.setList(list);
Product first = new Product("Burger");
Product second = new Product("Banana");
Cart cart1 = new Cart(1);
cart1.setType(1);
cart1.addElement(first);
cart1.addElement(second);
store.getCartList().add(cart1);
// create JAXB context and instantiate marshaller
JAXBContext context = JAXBContext.newInstance(Register.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
// Write to System.out
m.marshal(store, System.out);
m.marshal(store, new File("mrs.xml"));
System.out.println("Output from our XML File: ");
Unmarshaller um = context.createUnmarshaller();
Register reg = (Register) um.unmarshal(new FileReader("mrs.xml"));
ArrayList<Cart> list1 = reg.getCartList();
for(Cart x:reg.getCartList()) {
System.out.println(x.getId());
}
for (Cart cart : list1) {
System.out.println("Cart: " + cart.getId());
for(Product product : cart.getCart()) {
System.out.println("Product: " + product.getProduct());
}
}
}
}
So here is my output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<CashRegister>
<ShoppingCart CartIdentifier="1">
<CurrentProducts productName="Burger"/>
<CurrentProducts productName="Banana"/>
</ShoppingCart>
</CashRegister>
Output from our XML File:
0
Cart: 0
Product: null
Product: null
There is one cart with two products but not with 0 and null.
No, my question isn't duplicate. I don't want to have that as Element or show the name of that element in my xml. My xml looks perfect but i can't unmarshal it
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<CashRegister>
<ShoppingCart CartIdentifier="1">
<CurrentProducts productName="Burger"/>
<CurrentProducts productName="Banana"/>
</ShoppingCart>
</CashRegister>
Output from our XML File:
Exception in thread "main" java.lang.ClassCastException: bonusxml.Register cannot be cast to bonusxml.Register1
at bonusxml.Main.main(Main.java:45)
If you are hell bent on preserving your XML structure, you will have to pay a price for that. Below, are classes that can get you de-serializing the XML you have created. But, you will end up using two different set of classes for serializing and de-serializing.
Cart.java
#XmlRootElement(name="ShoppingCart")
public class Cart1 {
#XmlElement(name = "CurrentProducts")
private List<Product1> productList = new ArrayList<>();
#XmlAttribute(name="CartIdentifier")
private long CartIdentifier;
public Cart1() {}
public Cart1(long id) {
this.CartIdentifier=id;
}
// setters & getters
}
Product.java
public class Product1 {
#XmlAttribute(name = "productName")
private String name;
public Product1() {
}
public Product1(String name) {
this.name = name;
}
// setters & getters
}
Register.java
#XmlRootElement(name = "CashRegister")
public class Register1 {
#XmlElement(name = "ShoppingCart")
private ArrayList<Cart1> listCart;
long CartIdentifier;
public Register1() {
}
public Register1(long id) {
this.CartIdentifier=id;
}
//setters & getters
}

XML Namespace prefix d2lm on d2LogicalModel is not defined using jaxb

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

Java Unmarshal list of objects with a class wrapper with JAXB

From an XQuery performed by BaseX server I get a result like that:
<ProtocolloList>
<protocollo>
<numero>1</numero>
<data>2014-06-23</data>
<oggetto/>
<destinatario/>
<operatore/>
</protocollo>
...
</ProtocolloList>
And I need to convert this result in a List of Protocollo objects with JAXB so that I can show them with JList. Thus, following one of the discussions here I've declared the following classes:
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "protocollo")
public class Protocollo {
private int numero;
private String data;
private String oggetto;
private String destinatario;
private String operatore;
public Protocollo(String d, String o, String des, String op) {
this.data = d;
this.oggetto = o;
this.destinatario = des;
this.operatore = op;
}
public Protocollo() {
}
#XmlElement
public int getNumero() {
return numero;
}
public void setNumero(int numero) {
this.numero = numero;
}
#XmlElement
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
#XmlElement
public String getOggetto() {
return oggetto;
}
public void setOggetto(String oggetto) {
this.oggetto = oggetto;
}
#XmlElement
public String getDestinatario() {
return destinatario;
}
public void setDestinatario(String destinatario) {
this.destinatario = destinatario;
}
#XmlElement
public String getOperatore() {
return operatore;
}
public void setOperatore(String operatore) {
this.operatore = operatore;
}
}
and
import java.util.ArrayList;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "ProtocolloList")
public class ProtocolloList {
#XmlElementWrapper(name = "ProtocolloList")
#XmlElement(name = "protocollo")
private ArrayList<Protocollo> ProtocolloList;
public ArrayList<Protocollo> getProtocolloList() {
return ProtocolloList;
}
public void setProtocolloList(ArrayList<Protocollo> protocolloList) {
ProtocolloList = protocolloList;
}
}
and finally I execute the converion like that:
JAXBContext jaxbContext = JAXBContext.newInstance(Protocollo.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
StringReader reader = new StringReader(this.resultXML);
protocolli = (ProtocolloList) unmarshaller.unmarshal(reader);
And I keep on getting this exception:
unexpected element (uri:"", local:"ProtocolloList"). Expected elements are <{}protocollo>
I suppose I'm making some mistakes with annotations.
Can you help?
For your use case you do not need the #XmlElementWrapper annotation. This is because the ProtocolList element corresponds to your #XmlRootElement annotation. Then you need the #XmlElement annotation on the property to grab each of the list items.
#XmlRootElement(name = "ProtocolloList")
public class ProtocolloList {
private ArrayList<Protocollo> ProtocolloList;
#XmlElement(name = "protocollo")
public ArrayList<Protocollo> getProtocolloList() {
return ProtocolloList;
}
}
Note:
By default you should annotate the property. If you want to annotate the fields you should put #XmlAccessorType(XmlAccessType.FIELD) on your class.
UPDATE
You need to make sure your JAXBContext is aware of the root class. You can change your JAXBContext creation code to be the following:
JAXBContext jaxbContext = JAXBContext.newInstance(ProtocolloList.class);

parsing subnodes with Jersey

We are connecting to a third party using Jersey. We then want to extract the returned xml into our class. This is actually working fine except for one node in the xml that is in a subnode.
Here is the xml returned:
<response>
...
<langISO>en</langISO>
<acquirerAmount>1000</acquirerAmount>
<acquirerCurrency>GBP</acquirerCurrency>
<subXml>
<authCode>122958</authCode>
</subXml>
</response>
Note that the authCode node is in a subnode (called subXml).
OurResponse myriadResponse = response.getEntity(OurResponse.class);
Here is our class, but it is not parsing out the authCode
package com.xxx;
import javax.ws.rs.Consumes;
import javax.ws.rs.Path;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
#Consumes("application/xml")
public class OurResponse {
private String authCode;
#XmlElement(name = "subXml/authCode")
public String getAuthCode() {
return authCode;
}
#XmlElement(name = "subXml/authCode")
public void setAuthCode(String authCode) {
this.authCode = authCode;
}
}
You have a couple different options:
Option 1 - MOXy JAXB & #XmlPath
You could use the MOXy JAXB implementation and the #XmlPath extension to achieve the desired result:
import javax.xml.bind.annotation.XmlRootElement;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement(name="response")
public class OurResponse {
private String authCode;
#XmlPath("subXml/authCode/text()")
public String getAuthCode() {
return authCode;
}
public void setAuthCode(String authCode) {
this.authCode = authCode;
}
}
For more information see:
http://bdoughan.blogspot.com/2010/09/xpath-based-mapping-geocode-example.html
Option 2 - Any JAXB Impl and #XmlJavaTypeAdapter
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
#XmlRootElement(name="response")
public class OurResponse {
private String authCode;
#XmlJavaTypeAdapter(AuthCodeAdapter.class)
#XmlElement(name="subXml")
public String getAuthCode() {
return authCode;
}
public void setAuthCode(String authCode) {
this.authCode = authCode;
}
}
with
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class AuthCodeAdapter extends XmlAdapter<SubXml, String> {
#Override
public String unmarshal(SubXml v) throws Exception {
return v.getAuthCode();
}
#Override
public SubXml marshal(String v) throws Exception {
SubXml subXml = new SubXml();
subXml.setAuthCode(v);
return subXml;
}
}
and
public class SubXml {
private String authCode;
public String getAuthCode() {
return authCode;
}
public void setAuthCode(String authCode) {
this.authCode = authCode;
}
}
For more information see:
http://bdoughan.blogspot.com/2010/07/xmladapter-jaxbs-secret-weapon.html
I don't think you can annotate with XmlElement like that. You might need to create a seperate SubXml class;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name="response")
public class OurResponse
{
private String lang;
private String amt;
private String curr;
private SubXml subXml;
public OurResponse()
{
}
//Getters and setters
}
and
public class SubXml
{
private String authcode;
public SubXml()
{
}
public String getAuthcode()
{
return authcode;
}
public void setAuthcode(String authcode)
{
this.authcode = authcode;
}
}
Note that the only annotation you need is #XmlRootElement on the OurResponse class and you need to set the name; name="response".

Categories

Resources