Simple-XML - how to serialize derived classes in a collection? - java

I want to serialize a object hierarchy including a list of objects which derive from the base class 'Thing'. This works fine, including deserialization - but XML-Simple insists in writing an attribute which specifies the actual used Java-class
when I create a xml file with the java code below, the content is like this:
<example1>
<things>
<fruit class="com.mumpitz.simplexmltest.Apple" id="17">
<sugar>212</sugar>
</fruit>
<fruit class="com.mumpitz.simplexmltest.Orange" id="25" weight="11.2"/>
</things>
</example1>
but this is not what I want.
I'd like to have
<example1>
<things>
<apple id="17">
<sugar>212</sugar>
</apple>
<orange id="25" weight="11.2"/>
</things>
</example1>
'apple' and 'orange' elements without a class attribute, not 'fruit' with such an attribute. Is this possible?
(The second xml complies to a existing schema; adding extra attributes is not an option)
Here's the code:
package com.mumpitz.simplexmltest;
import java.io.File;
import java.util.ArrayList;
import org.simpleframework.xml.Attribute;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.ElementList;
import org.simpleframework.xml.Root;
import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister;
class Fruit {
#Attribute(name = "id")
protected final int id;
Fruit(
#Attribute(name = "id")
int id) {
this.id = id;
}
int getObjectId() {
return id;
}
}
#Root
class Apple extends Fruit {
private final int sugar;
#Element(type = Fruit.class)
public Apple(
#Attribute(name = "id")
int id,
#Element(name = "sugar")
int sugar) {
super(id);
this.sugar = sugar;
}
#Element(name = "sugar")
public int getSugar() {
return this.sugar;
}
#Override
public String toString() {
return "id: " + id + ", sugar: " + sugar;
}
}
#Root
class Orange extends Fruit {
#Attribute
public double weight;
public Orange(
#Attribute(name = "id")
int id) {
super(id);
}
#Override
public String toString() {
return "id: " + id + ", weight: " + weight;
}
}
#Root
public class Example1 {
#ElementList
public ArrayList<Fruit> things = new ArrayList<Fruit>();
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("things:\n");
for (int i=0; i<things.size(); i++) {
sb.append(" " + things.get(i).toString() + "\n");
}
return sb.toString();
}
//////////////////////////////////
static Example1 createDummy() {
Example1 d = new Example1();
d.things.add(new Apple(17, 212));
Orange or = new Orange(25);
or.weight = 11.2;
d.things.add(or);
return d;
}
static String msg;
static Example1 res;
static public String getMessage() {
String m = msg;
msg = null;
return m;
}
static public boolean write(String path) {
Serializer serializer = new Persister();
Example1 example = Example1.createDummy();
File result = new File(path);
try {
serializer.write(example, result);
} catch (Exception e) {
e.printStackTrace();
msg = e.getMessage();
return false;
}
return true;
}
static public boolean read(String path) {
Serializer serializer = new Persister();
File source = new File(path);
try {
res = serializer.read(Example1.class, source);
} catch (Exception e) {
e.printStackTrace();
msg = e.getMessage();
return false;
}
return true;
}
public static Object getResult() {
return res;
}
}

some hours later I found the solution. You simply have to
Read the manual
Use the #ElementListUnion annotation
package com.mumpitz.simplexmltest;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.simpleframework.xml.Attribute;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.ElementList;
import org.simpleframework.xml.ElementListUnion;
import org.simpleframework.xml.Root;
import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister;
// the base class
#Element
class Thing {
static int count=0;
Thing() {
this.id = ++count;
}
#Attribute
protected int id;
public int getId() {
return id;
}
}
// first derived class
#Element
class Car extends Thing {
#Attribute
private String name;
Car(#Attribute(name="name") String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public String toString() {
return "ID: " + id + " Car: " + name;
}
}
// second derived class
#Element
class House extends Thing {
#Attribute
private int price;
House(#Attribute(name="price") int price) {
this.price = price;
}
public int getPrice() {
return this.price;
}
#Override
public String toString() {
return "ID: " + id + " House: " + price;
}
}
// a class with a list of base class instances
#Root(name="ListOfThings")
public class Example4 {
// specify the derived classes used in the list
#ElementListUnion({
#ElementList(entry="house", inline=true, type=House.class),
#ElementList(entry="car", inline=true, type=Car.class)
})
private ArrayList<Thing> list = new ArrayList<Thing>();
public void add(Thing t) {
list.add(t);
}
public List<Thing> getProperties() {
return list;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Example4 contains " + list.size() + " elements:\n");
for (Thing t : list) {
sb.append(" " + t.toString() + "\n");
}
return sb.toString();
}
//////////////////////////////////
// test code
//////////////////////////////////
static String msg;
static Example4 res;
static public String getMessage() {
String m = msg;
msg = null;
return m;
}
static private Example4 createDummy() {
Example4 d = new Example4();
d.add(new Car("Mercedes"));
d.add(new House(34000000));
d.add(new Car("VW"));
d.add(new House(230000));
return d;
}
//////////////////////////////////
// serialize / deserialize
//////////////////////////////////
static public boolean write(String path) {
Serializer serializer = new Persister();
File result = new File(path);
Example4 example = Example4.createDummy();
try {
serializer.write(example, result);
} catch (Exception e) {
e.printStackTrace();
msg = e.getMessage();
return false;
}
return true;
}
static public boolean read(String path) {
Serializer serializer = new Persister();
File source = new File(path);
try {
res = serializer.read(Example4.class, source);
} catch (Exception e) {
e.printStackTrace();
msg = e.getMessage();
return false;
}
return true;
}
public static Object getResult() {
return res;
}
}

Related

Cannot deserialize instance of Class out of START_ARRAY token

I am trying to read the below data into a java object, but it is somehow failing.
Expected input data to my method getInternalNodeMetadata:
Event [status=PUBLISHED, header=EventHeader{bu_id='2', mart_id='null', eventProducer=DCSQUARE, eventType='CARRIER', eventTimestamp=Wed Oct 28 13:54:02 IST 2020, callbackEnpoint='http://test.com/test-app/services/carriers/3000', eventFulfiller=DCSQUARE, modeOfOperation=INSERT, additionalData='null', comments='null', tenants='[TenantInfo {bu_id=2, mart_id=2}]'}, payload=null]
public Flux<Event> getInternalNodeMetadata(Flux<Message<String>> message) {
System.out.println(message.toString());
return message.flatMap(it -> {
System.out.println("Payload: " + it.getPayload());
String eventMessage = it.getPayload().substring(5,it.getPayload().length());
System.out.println("eventMessage: " + eventMessage);
Event event = null;
try {
event = objectMapper.readValue(eventMessage, Event.class);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
List<Event> internalNodeMetadataList = new ArrayList<>();
internalNodeMetadataList.add(event);
return Flux.fromIterable(internalNodeMetadataList);
});
}
The above code is failing at the line
event = objectMapper.readValue(eventMessage, Event.class);
I have used jackson-databind: 2.11.4 jar ( for reading the value from object mapper class com.fasterxml.jackson.databind.ObjectMapper )
Error stacktrace:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `com.test.events.Event` out of START_ARRAY token
at [Source: (String)" [status=PUBLISHED, header=EventHeader{bu_id='2', mart_id='null', eventProducer=DCSQUARE, eventType='CARRIER', eventTimestamp=Wed Oct 28 13:54:02 IST 2020, callbackEnpoint='http://test.com/test-app/services/carriers/3000', eventFulfiller=DCSQUARE, modeOfOperation=INSERT, additionalData='null', comments='null', tenants='[TenantInfo {bu_id=2, mart_id=2}]'}, payload=null]"; line: 1, column: 2]
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)
at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1468)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1242)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1190)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeFromArray(BeanDeserializer.java:604)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:190)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:166)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4526)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3468)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3436)
at com.test.node.metadata.core.NodeMetadataServiceFacade.lambda$getInternalNodeMetadata$0(NodeMetadataServiceFacade.java:47)
Can some please help me out of this. Thanks in advance!
Here is my Event class
package com.test.events;
import java.io.Serializable;
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 = "Event",
propOrder = {"status", "header", "payload"}
)
#XmlRootElement(
name = "Event"
)
public class Event<T> implements Serializable {
private static final long serialVersionUID = 1L;
#XmlElement(
name = "status",
required = true
)
private Status status;
#XmlElement(
name = "header",
required = true
)
private EventHeader header;
private T payload;
public Event() {
this.status = Status.FAIL;
}
public Event(EventHeader header, T payload) {
this.status = Status.FAIL;
this.header = header;
this.payload = payload;
}
public EventHeader getHeader() {
if (this.header == null) {
this.header = new EventHeader();
}
return this.header;
}
public EventHeader setHeader(EventHeader header) {
this.header = header;
return this.header;
}
public T getPayload() {
return this.payload;
}
public Event setPayload(T payload) {
this.payload = payload;
return this;
}
public Status getStatus() {
return this.status;
}
public Event setStatus(Status status) {
this.status = status;
return this;
}
public String toString() {
return "Event [status=" + this.status + ", header=" + this.header + ", payload=" + this.payload + "]";
}
}
Here is my EventData class
package com.test.events;
import com.test.com.util.DateTypeAdapter;
import java.io.Serializable;
import java.util.Date;
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;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(
name = "EventHeader"
)
#XmlRootElement(
name = "EventHeader"
)
public class EventHeader implements Serializable {
private static final long serialVersionUID = 1L;
#XmlElement(
name = "WM_BU.ID",
required = true
)
private String bu_id;
#XmlElement(
name = "WM_MART.ID",
required = false
)
private String mart_id;
#XmlElement(
name = "EventProducer",
required = true
)
private EventHeader.CPSystem eventProducer;
#XmlElement(
name = "EventType",
required = true
)
private String eventType;
#XmlElement(
name = "EventTimestamp",
required = true
)
#XmlJavaTypeAdapter(DateTypeAdapter.class)
private Date eventTimestamp;
#XmlElement(
name = "CallbackEnpoint",
required = false
)
private String callbackEnpoint;
#XmlElement(
name = "EventFulfiller",
required = true
)
private EventHeader.CPSystem eventFulfiller;
#XmlElement(
name = "ModeOfOperation",
required = true
)
private EventHeader.ModeOfOperation modeOfOperation;
#XmlElement(
name = "AdditionalData",
required = false
)
private String additionalData;
#XmlElement(
name = "Comments",
required = false
)
private String comments;
#XmlElement(
name = "Tenants",
required = false
)
private List<TenantInfo> tenants;
public EventHeader() {
}
public EventHeader(String bu_id, String mart_id, EventHeader.CPSystem eventProducer, String eventType, Date eventTimestamp, String callbackEnpoint, EventHeader.CPSystem eventFulfiller, EventHeader.ModeOfOperation modeOfOperation, String additionalData, String comments) {
this.bu_id = bu_id;
this.mart_id = mart_id;
this.eventProducer = eventProducer;
this.eventType = eventType;
this.eventTimestamp = eventTimestamp;
this.callbackEnpoint = callbackEnpoint;
this.eventFulfiller = eventFulfiller;
this.modeOfOperation = modeOfOperation;
this.additionalData = additionalData;
this.comments = comments;
}
public EventHeader(String bu_id, String mart_id, EventHeader.CPSystem eventProducer, String eventType, Date eventTimestamp, String callbackEnpoint, EventHeader.CPSystem eventFulfiller, EventHeader.ModeOfOperation modeOfOperation, String additionalData, String comments, List<TenantInfo> tenants) {
this.bu_id = bu_id;
this.mart_id = mart_id;
this.eventProducer = eventProducer;
this.eventType = eventType;
this.eventTimestamp = eventTimestamp;
this.callbackEnpoint = callbackEnpoint;
this.eventFulfiller = eventFulfiller;
this.modeOfOperation = modeOfOperation;
this.additionalData = additionalData;
this.comments = comments;
this.tenants = tenants;
}
public String getBu_id() {
return this.bu_id;
}
public void setBu_id(String bu_id) {
this.bu_id = bu_id;
}
public String getMart_id() {
return this.mart_id;
}
public void setMart_id(String mart_id) {
this.mart_id = mart_id;
}
public EventHeader.CPSystem getEventProducer() {
return this.eventProducer;
}
public void setEventProducer(EventHeader.CPSystem eventProducer) {
this.eventProducer = eventProducer;
}
public String getEventType() {
return this.eventType;
}
public void setEventType(String eventType) {
this.eventType = eventType;
}
public Date getEventTimestamp() {
return this.eventTimestamp;
}
public void setEventTimestamp(Date eventTimestamp) {
this.eventTimestamp = eventTimestamp;
}
public String getCallbackEnpoint() {
return this.callbackEnpoint;
}
public void setCallbackEnpoint(String callbackEnpoint) {
this.callbackEnpoint = callbackEnpoint;
}
public EventHeader.CPSystem getEventFulfiller() {
return this.eventFulfiller;
}
public void setEventFulfiller(EventHeader.CPSystem eventFulfiller) {
this.eventFulfiller = eventFulfiller;
}
public EventHeader.ModeOfOperation getModeOfOperation() {
return this.modeOfOperation;
}
public void setModeOfOperation(EventHeader.ModeOfOperation modeOfOperation) {
this.modeOfOperation = modeOfOperation;
}
public String getAdditionalData() {
return this.additionalData;
}
public void setAdditionalData(String additionalData) {
this.additionalData = additionalData;
}
public String getComments() {
return this.comments;
}
public void setComments(String comments) {
this.comments = comments;
}
public List<TenantInfo> getTenants() {
return this.tenants;
}
public void setTenants(List<TenantInfo> tenants) {
this.tenants = tenants;
}
public String toString() {
return "EventHeader{bu_id='" + this.bu_id + '\'' + ", mart_id='" + this.mart_id + '\'' + ", eventProducer=" + this.eventProducer + ", eventType='" + this.eventType + '\'' + ", eventTimestamp=" + this.eventTimestamp + ", callbackEnpoint='" + this.callbackEnpoint + '\'' + ", eventFulfiller=" + this.eventFulfiller + ", modeOfOperation=" + this.modeOfOperation + ", additionalData='" + this.additionalData + '\'' + ", comments='" + this.comments + '\'' + ", tenants='" + this.tenants + '\'' + '}';
}
public static enum CPSystem {
DCSQUARE,
IMS,
OMS,
FOCI,
MCSE,
LMS,
LMDE,
SIMS,
GSCOPE,
PARTNER_MASTER,
PARTNER_PORTAL,
CAP,
SYNAPSE,
LIMO;
private CPSystem() {
}
}
public static enum ModeOfOperation {
INSERT,
UPDATE,
DELETE,
PUT,
POST;
private ModeOfOperation() {
}
}
}
Here is my DataTypeAdapter class
package com.test.common.util;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import javax.xml.bind.DatatypeConverter;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.datatype.DatatypeConfigurationException;
public class DateTypeAdapter extends XmlAdapter<String, Date> {
public static final String DATE_TIME_FORMAT_REGEX = "[0-9]{4}-(0[1-9]{1}|1[0-2]{1})-([0-2][0-9]|3[0-1])T([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(([.]([0-9]{3}))?+)[-+][0-9]{2}:[0-9]{2}";
public DateTypeAdapter() {
}
public Date unmarshal(String v) throws ParseException {
if (v != null && v.trim().length() > 0) {
try {
if (!v.matches("[0-9]{4}-(0[1-9]{1}|1[0-2]{1})-([0-2][0-9]|3[0-1])T([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(([.]([0-9]{3}))?+)[-+][0-9]{2}:[0-9]{2}")) {
throw new ParseException("Invalid date format provided. Allowed date format should follow the format {yyyy-MM-ddThh:mm:ss.millisecs-+Zone}. e.g. 2015-11-30T16:12:05.195-08:00", 0);
} else {
Calendar cal = DatatypeConverter.parseDateTime(v);
cal.setLenient(false);
return cal.getTime();
}
} catch (IllegalArgumentException var3) {
throw new ParseException("Invalid date format " + v, 0);
}
} else {
return null;
}
}
public String marshal(Date v) throws ParseException, DatatypeConfigurationException {
Calendar c = Calendar.getInstance();
c.setTime(v);
String dateTime = DatatypeConverter.printDateTime(c).replace("Z", "+00:00");
return dateTime;
}
}
You are sending an array of Events to "getInternalNodeMetadata" and trying to deserialize it to single Event, that is why you are getting the error , you need it to deserialize it to a list of events
event = objectMapper.readValue(eventMessage, Event.class);
Here you probably need to do something like
List<Event> eventList = mapper.readValue(eventMessage, List.class);

why JAXB java xml unmarshaller return null

I am trying to unmarshal XML to java class as follows:-
My xml file as follows:-
<Features_res>
<StartWeek>202017</StartWeek>
<EndWeek>202035</EndWeek>
<Pno12>ABCDEEB</Pno12>
<FeatureList>
<Feature>
<Code>T002</Code>
</Feature>
<Feature>
<Code>T002</Code>
</Feature>
</FeatureList>
</Features_res>
Java InteriorResponse:-
#XmlRootElement(name = "Features_res")
public class InteriorResponse {
#XmlElement(name = "StartWeek")
private int sWeek;
#XmlElement(name = "EndWeek")
private int eWeek;
#XmlElement(name = "Pno12")
private String p12;
List<Feature> featureList;
public InteriorResponse() {
}
public InteriorResponse(int startWeek, int endWeek, String pno12) {
super();
this.sWeek = startWeek;
this.eWeek = endWeek;
this.p12 = pno12;
}
public int getStartWeek() {
return sWeek;
}
public void setStartWeek(int startWeek) {
this.sWeek = startWeek;
}
public int getEndWeek() {
return eWeek;
}
public void setEndWeek(int endWeek) {
this.eWeek = endWeek;
}
public String getPno12() {
return p12;
}
public void setPno12(String pno12) {
this.p12 = pno12;
}
public List<Feature> getFeatureList() {
return featureList;
}
#XmlElement(name = "FeatureList")
public void setFeatureList(List<Feature> featureList) {
this.featureList = featureList;
}
}
Another Java Feature:-
#XmlRootElement(name = "Feature")
public class Feature {
//#XmlElement(name = "Feature")
private String feature_;
#XmlElement(name = "code")
private String code_;
public String getCode() {
return code_;
}
public void setCode(String code) {
this.code_ = code;
}
public String getFeature_() {
return feature_;
}
public void setFeature_(String feature_) {
this.feature_ = feature_;
}
}
I am using above class as :-
public static void xmlToInterior() {
File file = new File("minxml.xml");
JAXBContext jaxbContext;
try {
jaxbContext = JAXBContext.newInstance(InteriorResponse.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
InteriorResponse interiorFeatures = (InteriorResponse) unmarshaller.unmarshal(file);
List<Feature> list_feat = interiorFeatures.getFeatureList();
for(Feature ft : list_feat) {
System.out.println(ft.getCode());
}
} catch (JAXBException e) {
e.printStackTrace();
}
}
Output I have as:-
list_feat
code_ null
feature_ null
And list_feat has size 1. It should 2.
Also I have to name class member sWeek instead of startWeek. Otherwise, jaxbContext = JAXBContext.newInstance(InteriorResponse.class) throws exception like 2 element exist with same name.
XML additional part
I thought I could do the reaming part of the XML. I was trying part by part. But I couldn't do it. I really need to find some good tutorial or book about JXB. All I find a short overview of JXB. Any suggestion about where to read in details?
<Features_res>
<StartWeek>202017</StartWeek>
<EndWeek>202035</EndWeek>
<Pno12>ABCDEEB</Pno12>
<FeatureList>
<Feature>
<Code>T002</Code>
</Feature>
<Feature>
<Code>T002</Code>
</Feature>
</FeatureList>
<OptionList>
<Option>001048</Option>
<Option>000050</Option>
<Option>000790</Option>
</OptionList>
</Features_res>
So I made new class as:-
public class OptionList {
private List<Option> options;
#XmlElement(name = "Option")
public List<Option> getOptions() {
return options;
}
public void setOptions(List<Option> options) {
this.options = options;
}
}
Another class as :-
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;
public class Option {
#XmlElement(name = "Option")
private String option_;
public String getOption() {
return option_;
}
public void setOption(String option) {
this.option_ = option;
}
}
And updated for InteriorResponse class as:-
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "Features_res")
public class InteriorResponse {
#XmlElement(name = "StartWeek")
private int sWeek;
#XmlElement(name = "EndWeek")
private int eWeek;
#XmlElement(name = "Pno12")
private String p12;
private FeatureList featureList;
private OptionList optionList;
public InteriorResponse() {}
public InteriorResponse(int startWeek, int endWeek, String pno12) {
super();
this.sWeek = startWeek;
this.eWeek = endWeek;
this.p12 = pno12;
}
public int getStartWeek() {
return sWeek;
}
public void setStartWeek(int startWeek) {
this.sWeek = startWeek;
}
public int getEndWeek() {
return eWeek;
}
public void setEndWeek(int endWeek) {
this.eWeek = endWeek;
}
public String getPno12() {
return p12;
}
public void setPno12(String pno12) {
this.p12 = pno12;
}
#XmlElement(name = "FeatureList")
public FeatureList getFeatureList() {
return featureList;
}
public void setFeatureList(FeatureList featureList) {
this.featureList = featureList;
}
#XmlElement(name = "OptionList")
public OptionList getOptionList() {
return optionList;
}
public void setOptionList(OptionList optionList) {
this.optionList = optionList;
}
#Override
public String toString() {
return "InteriorResponse{"
+ "sWeek="
+ sWeek
+ ", eWeek="
+ eWeek
+ ", p12='"
+ p12
+ '\''
+ ", featureList="
+ featureList
+ '}';
}
}
I couldn't get the Option.
option null
The total xml is really huge. I still would like to try the remaing parts by myself part by part.
You need to design your classes according to XML structure. Find below the classes.
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "Features_res")
public class InteriorResponse {
#XmlElement(name = "StartWeek")
private int sWeek;
#XmlElement(name = "EndWeek")
private int eWeek;
#XmlElement(name = "Pno12")
private String p12;
private FeatureList featureList;
private OptionList optionList;
public InteriorResponse() {}
public InteriorResponse(int startWeek, int endWeek, String pno12) {
super();
this.sWeek = startWeek;
this.eWeek = endWeek;
this.p12 = pno12;
}
public int getStartWeek() {
return sWeek;
}
public void setStartWeek(int startWeek) {
this.sWeek = startWeek;
}
public int getEndWeek() {
return eWeek;
}
public void setEndWeek(int endWeek) {
this.eWeek = endWeek;
}
public String getPno12() {
return p12;
}
public void setPno12(String pno12) {
this.p12 = pno12;
}
#XmlElement(name = "FeatureList")
public FeatureList getFeatureList() {
return featureList;
}
public void setFeatureList(FeatureList featureList) {
this.featureList = featureList;
}
#XmlElement(name = "OptionList")
public OptionList getOptionList() {
return optionList;
}
public void setOptionList(OptionList optionList) {
this.optionList = optionList;
}
#Override
public String toString() {
return "InteriorResponse{"
+ "sWeek="
+ sWeek
+ ", eWeek="
+ eWeek
+ ", p12='"
+ p12
+ '\''
+ ", featureList="
+ featureList
+ ", optionList="
+ optionList
+ '}';
}
}
Class for Feature object
import javax.xml.bind.annotation.XmlElement;
public class Feature {
#XmlElement(name = "Code")
private String code_;
public String getCode() {
return code_;
}
public void setCode(String code) {
this.code_ = code;
}
#Override
public String toString() {
return "Feature{" + "code_='" + code_ + '\'' + '}';
}
}
Class for FeatureList
import javax.xml.bind.annotation.XmlElement;
import java.util.List;
public class FeatureList {
private List<Feature> features;
#XmlElement(name = "Feature")
public List<Feature> getFeatures() {
return features;
}
public void setFeatures(List<Feature> features) {
this.features = features;
}
}
Class for OptionList
import javax.xml.bind.annotation.XmlElement;
import java.util.List;
public class OptionList {
private List<String> option;
#XmlElement(name = "Option")
public List<String> getOption() {
return option;
}
public void setOption(List<String> option) {
this.option = option;
}
}
For testing and simplicity, I have written a small java test program below.
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.io.File;
import java.util.List;
public class Test {
public static void main(String[] args) {
File file =
new File("E:\\so\\xml\\minxml.xml");
JAXBContext jaxbContext;
try {
jaxbContext = JAXBContext.newInstance(InteriorResponse.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
InteriorResponse interiorFeatures = (InteriorResponse) unmarshaller.unmarshal(file);
List<Feature> list_feat = interiorFeatures.getFeatureList().getFeatures();
List<String> optionList = interiorFeatures.getOptionList().getOption();
for (String option : optionList) {
System.out.println("Option Value : " + option);
}
for (Feature ft : list_feat) {
System.out.println(ft.getCode());
}
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
I also provide the sample xml structure below.
<Features_res>
<StartWeek>202017</StartWeek>
<EndWeek>202035</EndWeek>
<Pno12>ABCDEEB</Pno12>
<FeatureList>
<Feature>
<Code>T002</Code>
</Feature>
<Feature>
<Code>T002</Code>
</Feature>
</FeatureList>
<OptionList>
<Option>001048</Option>
<Option>000050</Option>
<Option>000790</Option>
</OptionList>
</Features_res>
I knew very little about JAXB stuff. I have learned a lot from Sambit who helped a lot and gave me the way to start with this JAXB. Later I have implemented my version with less number of Java class and more smart use of JAXB annotations.
My version of InteriorResponse class:-
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
#XmlRootElement(name = "Features_res")
public class InteriorResponse {
#XmlElement(name = "StartWeek")
private int startWeek;
#XmlElement(name = "EndWeek")
private int endWeek;
#XmlElement(name = "Pno12")
private String pno12;
#XmlElementWrapper(name = "FeatureList")
#XmlElement(name = "Feature")
private List<Feature> featureList;
#XmlElementWrapper(name = "OptionList")
#XmlElement(name = "Option")
private List<String> optionList;
public InteriorResponse() {
}
public InteriorResponse(int startWeek, int endWeek, String pno12) {
super();
this.startWeek = startWeek;
this.endWeek = endWeek;
this.pno12 = pno12;
}
#XmlTransient
public int getStartWeek() {
return startWeek;
}
public void setStartWeek(int startWeek) {
this.startWeek = startWeek;
}
#XmlTransient
public int getEndWeek() {
return endWeek;
}
public void setEndWeek(int endWeek) {
this.endWeek = endWeek;
}
#XmlTransient
public String getPno12() {
return pno12;
}
public void setPno12(String pno12) {
this.pno12 = pno12;
}
#XmlTransient
public List<Feature> getFeatureList() {
return featureList;
}
public void setFeatureList(List<Feature> featureList) {
this.featureList = featureList;
}
#XmlTransient
public List<String> getOptionList() {
return optionList;
}
public void setOptionList(List<String> optionList) {
this.optionList = optionList;
}
#Override
public String toString() {
return "InteriorResponse{" + "sWeek=" + startWeek + ", eWeek=" + endWeek + ", pno12='" + pno12 + '\'' + ", featureList=" + featureList + ", optionList="
+ optionList + '}';
}
}
My version of Feature class:-
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;
public class Feature {
#XmlElement(name = "Code")
private String code;
#XmlTransient
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
#Override
public String toString() {
return "Feature{" + "code_='" + code + '\'' + '}';
}
}
Note that I don't need any extra wrapper class for FeatuerList and OptionList. It can be done by the JAXB annotation #XmlElementWrapper(name = "FeatureList"). Also, a very important lesson learned. We have to mark all the property's getter method as #XmlTransient. Otherwise, JAXB throws an exception 2 properties found with the same name. Because our class all properties is visible to the JAXB. So we have to mark one as #XmlTransient.
In my opion, it is a better solution than the accepted answer. I gave all the credit to Sambit. I hove this will help others.

Java.net(RestFul service JSON reponse parsing issue) How to convert list of same item in JSON reponse String to Java Object?

I am calling Restful service using below code :(Java.net implementation )
StringBuilder responseStrBuilder = new StringBuilder();
try
{
URL url = new URL(restUrl);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod(httpRequestMethod);
conn.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
conn.setRequestProperty("Content-Type", "application/json");
if (requestHeaders != null)
{
for (Map.Entry<String, String> entry : requestHeaders.entrySet())
{
conn.setRequestProperty(entry.getKey(), entry.getValue());
}
}
conn.setDoInput(true);
conn.setDoOutput(true);
OutputStream os = conn.getOutputStream();
os.write(urlParameters.getBytes());
os.flush();
os.close();
if (conn.getResponseCode() != 200) {//do something}
br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
while ((output = br.readLine()) != null)
responseStrBuilder.append(output);
Approach 1:
I have below string(JSON String) as my Restful service response , how can I convert it to Java object. Since same(Itm) object is repeated multiple times if I use org.codehaus.jettison.json.JSONObject myObject = new org.codehaus.jettison.json.JSONObject(responseStrBuilder.toString());
It only reads first Itm Object and does not bring list of all item object.
JSON String output from service :
{"Response":{"RID":"04'34'",
"Itm":{"id":{"ab":"1","cd":"12"},"qw":"JK","name":"abcd "},
"Itm":{"id":{"ab":"2","cd":"34},"qw":"JK","name":"asdf "},
"Itm":{"id":{"ab":"3","cd":"12"},"qw":"JK","name":"fghj "}
}}
Approach 2:
I also tried below snippet with correct Java object with setters and getters
ObjectMapper objectMapper = new ObjectMapper();
mapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
MyJavaReponseObject javaObj = mapper.readValue(json, MyJavaReponseObject.class);
This approach also reads only one object of Itm and not all the object as its not coming in array format in JSON string. Is there any better way of getting all the object(Itm) mapped to single List of Object in java pojo ?
You can use the List class in your response object, if you should parse that json string itself.
I have a ReponseJSON class with json objects, one Response and three Itms
static class ReponseJSON {
private Response Response;
#JsonProperty("Response")
public Response getResponse() {
return Response;
}
public void setResponse(Response Response) {
this.Response = Response;
}
static class Response {
private String rid;
private Itm Itm;
private List<Itm> listItm = new ArrayList<Itm>();
public Itm getItm() {
return Itm;
}
#JsonProperty("Itm")
public void setItm(Itm Itm) {
this.Itm = Itm;
listItm.add(Itm);
}
public String getRID() {
return rid;
}
public List<Itm> getItms() {
return listItm;
}
#JsonProperty("RID")
public void setRID(String rid) {
this.rid = rid;
}
static class Itm {
private Id id;
private String qw, name;
public String getQw() {
return qw;
}
public void setQw(String qw) {
this.qw = qw;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Id getId() {
return id;
}
public void setId(Id id) {
this.id = id;
}
static class Id {
private String ab, cd;
public String getCd() {
return cd;
}
public void setCd(String cd) {
this.cd = cd;
}
public String getAb() {
return ab;
}
public void setAb(String ab) {
this.ab = ab;
}
}
}
}
}
In a Response class, I have a list class and save a Itm object whenever object mapper call this class.
static class Response {
... skip ..
private List<Itm> listItm = new ArrayList<Itm>();
... skip ..
#JsonProperty("Itm")
public void setItm(Itm Itm) {
this.Itm = Itm;
listItm.add(Itm);
}
}
Check the full source code as follows.
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonParserTest {
static class ReponseJSON {
private Response Response;
#JsonProperty("Response")
public Response getResponse() {
return Response;
}
public void setResponse(Response Response) {
this.Response = Response;
}
static class Response {
private String rid;
private Itm Itm;
private List<Itm> listItm = new ArrayList<Itm>();
public Itm getItm() {
return Itm;
}
#JsonProperty("Itm")
public void setItm(Itm Itm) {
this.Itm = Itm;
listItm.add(Itm);
}
public String getRID() {
return rid;
}
public List<Itm> getItms() {
return listItm;
}
#JsonProperty("RID")
public void setRID(String rid) {
this.rid = rid;
}
static class Itm {
private Id id;
private String qw, name;
public String getQw() {
return qw;
}
public void setQw(String qw) {
this.qw = qw;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Id getId() {
return id;
}
public void setId(Id id) {
this.id = id;
}
static class Id {
private String ab, cd;
public String getCd() {
return cd;
}
public void setCd(String cd) {
this.cd = cd;
}
public String getAb() {
return ab;
}
public void setAb(String ab) {
this.ab = ab;
}
}
}
}
}
public static void main(String[] args) {
String responseJson =
"{\"Response\":{\"RID\":\"04'34'\","
+ "\"Itm\":{\"id\":{\"ab\":\"1\",\"cd\":\"12\"},\"qw\":\"JK\",\"name\":\"abcd\"}"
+ ",\"Itm\":{\"id\":{\"ab\":\"2\",\"cd\":\"34\"},\"qw\":\"JK\",\"name\":\"asdf\"}"
+ ",\"Itm\":{\"id\":{\"ab\":\"3\",\"cd\":\"12\"},\"qw\":\"JK\",\"name\":\"fghj\"}"
+ "}} ";
ObjectMapper mapper = new ObjectMapper();
ReponseJSON responseObj = null;
try {
responseObj = mapper.readValue(responseJson, ReponseJSON.class);
ReponseJSON.Response response = responseObj.getResponse();
for(int i = 0; i < response.getItms().size(); i++)
{
ReponseJSON.Response.Itm item = response.getItms().get(i);
System.out.println(item.getId().getAb());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
The version of my jackson mapper is 2.9.1.
You check the main method of the source, because the JSON string you prepared is invalid as coddemonkey mentioned.
Have a good day.
Make your json response looks something similar to this
{"Response":{"RID":"04'34'",
"Itms":[{"id":{"ab":"1","cd":"12"},"qw":"JK","name":"abcd "},
{"id":{"ab":"2","cd":"34"},"qw":"JK","name":"asdf "},
{"id":{"ab":"3","cd":"12"},"qw":"JK","name":"fghj "}]
}}
then, use org.json jar to parse the string to jsonObject
JSONObject jsonObject=new JSONObject(responseString);
This is one type of solution, if you can't change the response as mentioned above then you have to manually parse the string(using java bean) there is no other option available.

Polymorphism java loop error

I'm having a problem regarding a polymorphic invocation inside a loop.
I have an abstract class called Item that has two subclasses ClothingItem and SportItem and an abstract method called printBudgetGST(Items[] item) to return a string of an item with updated pricing which include tax.
Item Class :
public abstract class Item
{
private int code;
private double price;
private boolean isOnGST;
public Item()
{
}
public Item(int code,double price,boolean isOnGST)
{
this.code = code;
this.price = price;
this.isOnGST = isOnGST;
}
public void setGST(boolean isgst)
{
this.isOnGST = isgst;
}
public int getCode()
{
return code;
}
public boolean getIsOnGST()
{
return isOnGST;
}
public double getCurrentPrice()
{
return price;
}
public String toString() {
return "Item [code=" + code + ", price=" + price + ", isOnGST=" + isOnGST + "]";
}
public abstract String printBudgetGST(Item[] items);
}
ClothingItem class
public class ClothingItem extends Item
{
public ClothingItem(){
}
public ClothingItem(int code,double price,boolean isOnGST)
{
super(code,price,isOnGST);
}
#Override
public String printBudgetGST(Item[] item)
{
String stringitem ="";
for(int i=0;i<item.length;i++)
{
if(item[i].getIsOnGST()==true&&item[i].getCurrentPrice()<100.00)
{
double finalprice =(0.06*item[i].getCurrentPrice())+item[i].getCurrentPrice();
stringitem = stringitem + " " + "ClothingItem : " + item[i].getCode()+":"+"RM"+finalprice;
}
}
return stringitem;
}
}
SportsItem class:
public class SportsItem extends Item
{
public SportsItem(){
}
public SportsItem(int code,double price,boolean isOnGST)
{
super(code,price,isOnGST);
}
public String printBudgetGST(Item[] item)
{
String stringitem = "";
for(int i=0;i<item.length;i++)
{
if(item[i].getIsOnGST()==true &&item[i].getCurrentPrice()<150.00)
{
double finalprice =(0.06*item[i].getCurrentPrice())+item[i].getCurrentPrice();
stringitem = stringitem + "SportsItem : " + item[i].getCode()+":"+"RM"+finalprice;
}
}
return stringitem;
}
}
Test class :
public class Retail_Item
{
private Item[] itemList;
public Retail_Item()
{
itemList = new Item[10];
itemList[0] = new ClothingItem(10001,85,true);
itemList[1] = new ClothingItem(10002,150,false);
itemList[2] = new ClothingItem(10003,168,true);
itemList[3] = new ClothingItem(10004,43,true);
itemList[4] = new ClothingItem(10005,162,false);
itemList[5] = new SportsItem(10006,178,false);
itemList[6] = new SportsItem(10007,80,true);
itemList[7] = new SportsItem(10008,191,false);
itemList[8] = new SportsItem(10009,45,true);
itemList[9] = new SportsItem(10010,121,true);
}
public void printItem()
{
for(int i =0 ;i<itemList.length;i++)
{
if(itemList[i].getIsOnGST()==true && itemList[i].printBudgetGST(itemList).length()>0)
{
System.out.println(itemList[i].printBudgetGST(itemList));
}
}
}
}
public class TestRetailItem {
public static void main(String[] args)
{
Retail_Item ret = new Retail_Item();
ret.printItem();
}
}
OUTPUT :
The output should return a list of items which is on tax(GST) and with the updated pricing information like the example below
The problem is that you are passing to printBudgetGST the whole array of items and iterating over that array inside your implementations of printBudgetGST. Instead, you should remove that parameter and inside printBudgetGST you should simply call getCurrentPrice() and getCode() on this rather than on each item[i].
In addition, you are doing the check for maximum price (< 100 or < 150) inside the item subclasses but it's best to do this alongside the other checks in printItem. Because the max price depends on the subclass (SportsItem vs ClothinItem) I recommend you to create an abstract method boolean isOnBudget() in Item and implement accordingly in those two subclasses.
A fully fixed version of your code is
public abstract class Item {
private int code;
private double price;
private boolean isOnGST;
public Item()
{
}
public Item(int code,double price,boolean isOnGST)
{
this.code = code;
this.price = price;
this.isOnGST = isOnGST;
}
public void setGST(boolean isgst)
{
this.isOnGST = isgst;
}
public int getCode()
{
return code;
}
public boolean getIsOnGST()
{
return isOnGST;
}
public double getCurrentPrice()
{
return price;
}
public String toString() {
return "Item [code=" + code + ", price=" + price + ", isOnGST=" + isOnGST + "]";
}
public abstract String printBudgetGST();
public abstract boolean isOnBudget();
}
class ClothingItem extends Item {
public ClothingItem() {
}
public ClothingItem(int code, double price, boolean isOnGST) {
super(code, price, isOnGST);
}
#Override
public String printBudgetGST() {
String stringitem = "";
double finalprice = (0.06 * getCurrentPrice()) + getCurrentPrice();
stringitem = stringitem + " " + "ClothingItem : " + getCode() + ":" + "RM" + finalprice;
return stringitem;
}
#Override
public boolean isOnBudget() {
return getCurrentPrice() < 100.00;
}
}
class SportsItem extends Item {
public SportsItem() {
}
public SportsItem(int code, double price, boolean isOnGST) {
super(code, price, isOnGST);
}
public String printBudgetGST() {
String stringitem = "";
double finalprice = (0.06 * getCurrentPrice()) + getCurrentPrice();
stringitem = stringitem + "SportsItem : " + getCode() + ":" + "RM" + finalprice;
return stringitem;
}
#Override
public boolean isOnBudget() {
return getCurrentPrice() < 150.00;
}
}
class Retail_Item
{
private Item[] itemList;
public Retail_Item()
{
itemList = new Item[10];
itemList[0] = new ClothingItem(10001,85,true);
itemList[1] = new ClothingItem(10002,150,false);
itemList[2] = new ClothingItem(10003,168,true);
itemList[3] = new ClothingItem(10004,43,true);
itemList[4] = new ClothingItem(10005,162,false);
itemList[5] = new SportsItem(10006,178,false);
itemList[6] = new SportsItem(10007,80,true);
itemList[7] = new SportsItem(10008,191,false);
itemList[8] = new SportsItem(10009,45,true);
itemList[9] = new SportsItem(10010,121,true);
}
public void printItem() {
for(int i =0 ;i<itemList.length;i++) {
if(itemList[i].getIsOnGST()==true && itemList[i].printBudgetGST().length()>0 && itemList[i].isOnBudget())
{
System.out.println(itemList[i].printBudgetGST());
}
}
}
}
class TestRetailItem {
public static void main(String[] args) {
Retail_Item ret = new Retail_Item();
ret.printItem();
}
}

Rhino Evaluating a javascript object in Java

Im quite new to Rhino and trying to convert a javascript object to a java object but unable to do so. It doesnt seem to evaluate properly.
The javascript that I have is,
var myObject = new Object();
myObject.string1 = 'Hello';
myObject.string2 = 'World';
myObject.id = 1;
var parser = new Packages.com.MyParser();
var returnStr = parser.PrintObj(myObject);
And I have the following java class that I want to evaluate this to,
public class Person extends ScriptableObject {
private int id;
private String string1;
private String string2;
public Person() {}
public void jsConstructor() {
this.string1 = "";
this.string2 = "";
this.id = 0;
}
public int getID()
{
return this.id;
}
public void jsSet_id(int value)
{
this.id = value;
}
public int jsGet_id()
{
return this.id;
}
public String jsGet_string1()
{
return this.string1;
}
public void jsSet_string1(String value)
{
this.string1 = value;
}
public String jsGet_string2() {
return this.string2;
}
public void jsSet_string2(String value)
{
this.string2 = value;
}
#Override
public String toString() {
return id + " " + string1 + " " + string2;
}
#Override
public String getClassName() {
return "Person";
}
And the skeleton of my parser is,
public class MyParser {
public String PrintObj(ScriptableObject obj) {
// Need to convert to Person object here
// Obviously casting doesnt work here
return null;
}
}
Thanks
OK figured it out !
First of all i needed to define the class in javascript as. It was complaining at first it couldn't find the class without the namespace "com". Had to add that...
defineClass("com.Person")
var myObject = new Person();
myObject.string1 = 'Hello';
myObject.string2 = 'World';
myObject.id = 1;
var parser = new Packages.com.MyParser();
var returnStr = parser.PrintObj(myObject);
And then in the parser I added the following,
public String PrintObj(ScriptableObject obj) {
try {
Person pObj = (Person)Context.jsToJava(obj, Person.class);
System.out.println("Printing person: " + pObj);
}
catch (Exception e) {
e.printStackTrace();
}
return null;
}

Categories

Resources