JAVA/JAXB : Marshal/UnMarshal using attributes in the xml or class members - jaxb

I have XML as follows
<request type="1">
<request-header/>
<request-details>
<!-- Some more tags -->
</request-details>
</request>
For mapping this XML I have class structure as follows :
public class Request1
{
private RequestDetail_1;
//other members
}
public class Request2
{
private RequestDetail_2;
//other members
}
public class RequestDetail_1
{
//members
}
public class RequestDetail_2
{
//Members
}
What I want to do is ... If attribute type is 1 then I need to create object of type Request_1 , if type is 2 then object type will be Request_2 and so on.
I have gone through this link for reference but still couldn't figure out a way to do this. I want to use pure JAXB and not MOXY or any other such frame works... :( .
Partial code :
#XmlJavaTypeAdapter(RequestAdaptor.class)
#XmlRootElement(name="request")
public class AuthRequest extends Request
{
private AuthRequestDetails requestDetails;
public RequestDetails getRequestDetails()
{
return requestDetails;
}
#Override
public void setRequestDetails(RequestDetails requestDetails)
{
this.requestDetails = (AuthRequestDetails)requestDetails;
}
}
#XmlAccessorType(XmlAccessType.FIELD)
public class AuthRequestDetails extends RequestDetails
{
#XmlElement(name="user-name")
private String userName;
#XmlElement(name="password")
private String password;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlJavaTypeAdapter(RequestAdaptor.class)
public abstract class Request
{
#XmlAttribute
protected String type;
#XmlElement(name="request-header")
protected RequestHeader requestHeader;
public RequestHeader getRequestHeader()
{
return requestHeader;
}
public void setRequestHeader(RequestHeader requestHeader)
{
this.requestHeader = requestHeader;
}
public String getType()
{
return type;
}
public void setType(String type)
{
this.type = type;
}
public abstract void setRequestDetails(RequestDetails requestDetails);
public abstract RequestDetails getRequestDetails();
}
public class RequestAdaptor extends XmlAdapter<RequestDTO, Request>
{
#Override
public RequestDTO marshal(Request v) throws Exception
{
System.out.println("marshal");
RequestDTO lRequestDTO= new RequestDTO();
lRequestDTO.setRequestHeader(v.getRequestHeader());
lRequestDTO.setType(v.getType());
if(v.getType().equals("5"))
{
AuthRequest lRequest = (AuthRequest)v;
}
else
{
PingRequest lRequest = (PingRequest)v;
}
return lRequestDTO;
}
#Override
public Request unmarshal(RequestDTO v) throws Exception
{
System.out.println("unmarshal");
if(v.getType().equals("5"))
{
AuthRequest lRequest = new AuthRequest();
lRequest.setRequestHeader(v.getRequestHeader());
lRequest.setType(v.getType());
return lRequest;
}
else
{
PingRequest lRequest = new PingRequest();
lRequest.setRequestHeader(v.getRequestHeader());
lRequest.setType(v.getType());
return lRequest;
}
}
}
#XmlAccessorType(XmlAccessType.FIELD)
public class RequestDTO
{
#XmlAttribute
protected String type;
#XmlElement(name="request-header")
private RequestHeader requestHeader;
#XmlElement(name="request-details")
private RequestDetails requestDetails;
public RequestHeader getRequestHeader()
{
return requestHeader;
}
public void setRequestHeader(RequestHeader requestHeader)
{
this.requestHeader = requestHeader;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public RequestDetails getRequestDetails() {
return requestDetails;
}
public void setRequestDetails(RequestDetails requestDetails) {
this.requestDetails = requestDetails;
}
}
#XmlAccessorType(XmlAccessType.FIELD)
public class RequestHeader
{
#XmlElement(name="name")
String Name;
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
}
First thing is : Marshal and Unmarshal of Adaptor is not getting called. I am stuck at this point.

You can use a StAX XmlStreamReader to parse the XML. Then advance it to the root element. When it's at the root element event check the value of the type attribute. Use this value to determine which Class you should pass to the unmarshal method that takes a Class and XmlStreamReader to get the result you are looking for.

Related

Model mapper mapping Map<String,Object> to class which extends another generic class not working for list field

I am trying to create my custom configuration object from Map using model mapper. Everything gets mapped properly excepts the fields property which is coming fro Generic super class.
My target object is
public class ADParserConfig extends CustomParserConfig<ADParserConfigField> {
private String pattern;
public String getPattern() {
return pattern;
}
public void setPattern(String pattern) {
this.pattern = pattern;
}
}
This extends generic class CustomParserConfig
public class CustomParserConfig<T extends CustomParserConfigField> {
protected List<T> fields;
protected String timeStampField;
public List<T> getFields() {
return fields;
}
public void setFields(List<T> fields) {
this.fields = fields;
}
public String getTimeStampField() {
return timeStampField;
}
public void setTimeStampField(String timeStampField) {
this.timeStampField = timeStampField;
}
}
Where CustomParserConfigField is
public class CustomParserConfigField {
protected String name;
protected Integer index;
protected String type;
protected String format;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getIndex() {
return index;
}
public void setIndex(Integer index) {
this.index = index;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getFormat() {
return format;
}
public void setFormat(String format) {
this.format = format;
}
}
I am trying to map Map using below function
ADParserConfig adParserConfig = getConfig(map,ADParserConfig.class);
public <T extends CustomParserConfig> T getConfig(Map<String,Object> configObject, Class<T> classType){
ModelMapper modelMapper = new ModelMapper();
return modelMapper.map(configObject,classType);
}
Everything excepts fields gets mapped properly for the below map.
{fields=[{name=timeStamp, type=timestamp, format=dd/mm/yyyy HH:MM:SS a}, {name=logName, type=string}], pattern=(?<timeStamp>\d{2}\/\d{2}\/\d{4}\s\d{2}:\d{2}:\d{2}\s[AMPMampm]{2})?\s(LogName=(?<logName>[\w\s\W]+))?\sSourceName=(?<sourceName>[\w\s\W]+)\sEventCode=(?<eventCode>[0-9]*), timeStampField=timestamp}
Please help. Why is issue happens only for fields object ? Do I need to specify something else in mapper configurations ?
It looks like a bug and it had been fixed by #370

Field attribute is coming as null while unmarshalling an xml file

Hi I am trying to convert an xml file into Java Objects using JAXB and I am very new to java. I have created the pojo classes and added some annotations but I am not sure whether they are right? I have spent hours in google but couldn't find what is wrong.
This is my xml :
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<question id="1">
<answers>
<answername>java is a programming language</answername>
<id>101</id>
<postedby>ravi</postedby>
</answers>
<answers>
<answername>java is a platform</answername>
<id>102</id>
<postedby>john</postedby>
</answers>
<questionname>What is java?</questionname>
<marks set=50>
<longAnswer set=45/>
<shortAnswer set=30/>
</marks>
</question>
Pojo classes:
#XmlRootElement(name="question")
public class Question {
private int id;
private String questionname;
private List<Answer> answers;
private List<Marks> marks;
public Question() {}
public Question(int id, String questionname, List<Answer> answers, List<Marks> marks) {
super();
this.id = id;
this.questionname = questionname;
this.answers = answers;
this.marks = marks;
}
#XmlElement(name="marks")
public List<Marks> getMarks() {
return marks;
}
public void setMarks(List<Marks> marks) {
this.marks = marks;
}
#XmlAttribute
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#XmlElement
public String getQuestionname() {
return questionname;
}
public void setQuestionname(String questionname) {
this.questionname = questionname;
}
#XmlElement
public List<Answer> getAnswers() {
return answers;
}
public void setAnswers(List<Answer> answers) {
this.answers = answers;
}
}
public class Answer {
private int id;
private String answername;
private String postedby;
public Answer() {}
public Answer(int id, String answername, String postedby) {
super();
this.id = id;
this.answername = answername;
this.postedby = postedby;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getAnswername() {
return answername;
}
public void setAnswername(String answername) {
this.answername = answername;
}
public String getPostedby() {
return postedby;
}
public void setPostedby(String postedby) {
this.postedby = postedby;
}
}
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
public class Marks {
private LongAnswer longAnswer ;
private ShortAnswer shortAnswer;
private String set;
#XmlAttribute
public String getSet() {
return set;
}
public void setSet(String set) {
this.set = set;
}
#XmlElement(name="longAnswer")
public LongAnswer getLongAnswer() {
return longAnswer;
}
public void setLongAnswer(LongAnswer longAnswer) {
this.longAnswer = longAnswer;
}
#XmlElement(name="shortAnswer")
public ShortAnswer getShortAnswer() {
return shortAnswer;
}
public void setShortAnswer(ShortAnswer shortAnswer) {
this.shortAnswer = shortAnswer;
}
}
public class LongAnswer {
private String set;
public String getSet() {
return set;
}
public void setSet(String set) {
this.set = set;
}
public class ShortAnswer {
private String set;
public String getSet() {
return set;
}
public void setSet(String set) {
this.set = set;
}
}
Can anyone tell me how to annotate the 'marks' model class and how to set 'longAnswer' and 'shortAnswer' field. Because i am getting null values for them.
You should annotate your set properties with #XmlAttribute. Otherwise it looks quite fine.
What you could also do is create an XML Schema for you XML and compile it.

JaxB Marshaling in camel

I am new to Apache camel and Jax b concept in java.
I have a list of java objects in a camel queue. I want to Marshall it to an xml with Javs DSL(without using spring).
Could any one guide me to do that?
I have the following POJO class
public class MyPojo {
private int groupId;
private int memberId;
private String details;
public int getgroupId() {
return groupId;
}
public void setgroupId(int groupId) {
this.groupId = groupId;
}
public int getMemberId() {
return memberId;
}
public void setMemberId(int memberId) {
this.memberId = memberId;
}
public String getdetails() {
return details;
}
public void setdetails(String details) {
this.details = details;
}}
following is my camel code for jaxb implementation
JaxbDataFormat jaxbMarshal = new JaxbDataFormat();
jaxbMarshal.setContextPath("com.test");
jaxbMarshal.setPartClass("com.test.MyPojo");
from("direct:javaObjects") //this direct having the list of MYPojo Objects
.marshal(jaxbMarshal)
.to("src/output");
I am getting below exception(I added maven dependency for jaxb in classpath)
Failed to create route route4 at: >>> Marshal[org.apache.camel.model.dataformat.JaxbDataFormat#3feb2dda] <<< in route: Route(route4)[[From[direct:javaObjects]] -> [Marshal[org.apa... because of Data format 'jaxb' could not be created. Ensure that the data format is valid and the associated Camel component is present on the classpath
I have created the jaxb.index file(new->File from eclipse). the content of the file should be annotation class name
In our case it should be
MyPojo
and its needs to be placed in context path. in our case it should be placed in
com.test location
and the annotated Pojo class is
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement
public class MyPojo {
#XmlElement
private int groupId;
#XmlElement
private int memberId;
#XmlElement
private String details;
public int getgroupId() {
return groupId;
}
public void setgroupId(int groupId) {
this.groupId = groupId;
}
public int getMemberId() {
return memberId;
}
public void setMemberId(int memberId) {
this.memberId = memberId;
}
public String getdetails() {
return details;
}
public void setdetails(String details) {
this.details = details;
}}
You can use your pojo with some annotations:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name="MY-POJO")
#XmlType(propOrder = {"groupId", "memberId", "details"})
public class MyPojo {
#XmlElement(name = "groupId")
private int groupId;
#XmlElement(name = "memberId")
private int memberId;
#XmlElement(name = "details")
private String details;
public int getgroupId() {
return groupId;
}
public void setgroupId(int groupId) {
this.groupId = groupId;
}
public int getMemberId() {
return memberId;
}
public void setMemberId(int memberId) {
this.memberId = memberId;
}
public String getdetails() {
return details;
}
public void setdetails(String details) {
this.details = details;
}}

response.body returns null using retrofit:2.3.0

my json data is this
{
"data":[
{
"id":"4",
"totalOpns":"40000",
"killedDrugPer":"320",
"arrestedDrugPer":"17683",
"houseVisited":"4000",
"userSurrenderers":"45000",
"pusherSurrenderers":"15000",
"totalSurrenderers":"60000",
"killedPNPPerOpns":"40",
"woundedPNPPerOpns":"70",
"killedAFPPerOpns":"100",
"woundedAFPPerOpns":"10",
"date":"2017-07-12 13:57:34.000"
}
]
}
and my data model is this
package com.androidtutorialpoint.retrofitandroid;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import java.io.Serializable;
public class Student implements Serializable {
//Variables that are in our json
#SerializedName("id")
#Expose
private String id;
#SerializedName("totalOpns")
#Expose
private String totalOpns;
#SerializedName("killedDrugPer")
#Expose
private String killedDrugPer;
#SerializedName("arrestedDrugPer")
#Expose
private String arrestedDrugPer;
#SerializedName("houseVisited")
#Expose
private String houseVisited;
#SerializedName("userSurrenderers")
#Expose
private String userSurrenderers;
#SerializedName("pusherSurrenderers")
#Expose
private String pusherSurrenderers;
#SerializedName("totalSurrenderers")
#Expose
private String totalSurrenderers;
#SerializedName("killedPNPPerOpns")
#Expose
private String killedPNPPerOpns;
#SerializedName("woundedPNPPerOpns")
#Expose
private String woundedPNPPerOpns;
#SerializedName("killedAFPPerOpns")
#Expose
private String killedAFPPerOpns;
#SerializedName("woundedAFPPerOpns")
#Expose
private String woundedAFPPerOpns;
#SerializedName("date")
#Expose
private String date;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTotalOpns() {
return totalOpns;
}
public void setTotalOpns(String totalOpns) {
this.totalOpns = totalOpns;
}
public String getKilledDrugPer() {
return killedDrugPer;
}
public void setKilledDrugPer(String killedDrugPer) {
this.killedDrugPer = killedDrugPer;
}
public String getArrestedDrugPer() {
return arrestedDrugPer;
}
public void setArrestedDrugPer(String arrestedDrugPer) {
this.arrestedDrugPer = arrestedDrugPer;
}
public String getHouseVisited() {
return houseVisited;
}
public void setHouseVisited(String houseVisited) {
this.houseVisited = houseVisited;
}
public String getUserSurrenderers() {
return userSurrenderers;
}
public void setUserSurrenderers(String userSurrenderers) {
this.userSurrenderers = userSurrenderers;
}
public String getPusherSurrenderers() {
return pusherSurrenderers;
}
public void setPusherSurrenderers(String pusherSurrenderers) {
this.pusherSurrenderers = pusherSurrenderers;
}
public String getTotalSurrenderers() {
return totalSurrenderers;
}
public void setTotalSurrenderers(String totalSurrenderers) {
this.totalSurrenderers = totalSurrenderers;
}
public String getKilledPNPPerOpns() {
return killedPNPPerOpns;
}
public void setKilledPNPPerOpns(String killedPNPPerOpns) {
this.killedPNPPerOpns = killedPNPPerOpns;
}
public String getWoundedPNPPerOpns() {
return woundedPNPPerOpns;
}
public void setWoundedPNPPerOpns(String woundedPNPPerOpns) {
this.woundedPNPPerOpns = woundedPNPPerOpns;
}
public String getKilledAFPPerOpns() {
return killedAFPPerOpns;
}
public void setKilledAFPPerOpns(String killedAFPPerOpns) {
this.killedAFPPerOpns = killedAFPPerOpns;
}
public String getWoundedAFPPerOpns() {
return woundedAFPPerOpns;
}
public void setWoundedAFPPerOpns(String woundedAFPPerOpns) {
this.woundedAFPPerOpns = woundedAFPPerOpns;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
}
and the interface is this
package com.androidtutorialpoint.retrofitandroid;
import retrofit2.Call;
import retrofit2.http.GET;
public interface RetrofitObjectAPI {
/*
* Retrofit get annotation with our URL
* And our method that will return us details of student.
*/
// #GET("JSONTESTING/index.php")
#GET("getJson")
Call<Student> getStudentDetails();
}
and in my main is this
private void getRetrofitObject() {
HttpLoggingInterceptor.Level logLevel = HttpLoggingInterceptor.Level.BODY;
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
// set your desired log level
logging.setLevel(logLevel);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
// add your other interceptors …
// add logging as last interceptor
httpClient.addInterceptor(logging); // <-- this is the important line!
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.client(httpClient.build())
.build();
RetrofitObjectAPI service = retrofit.create(RetrofitObjectAPI.class);
Call<Student> call = service.getStudentDetails();
call.enqueue(new Callback<Student>() {
#Override
public void onResponse(Call<Student> call, Response<Student> response) {
try {
if (response.isSuccessful()) {
text_id_1.setText("StudentId : " + response.body().getId());
text_name_1.setText("StudentName : " + response.body().getTotalOpns());
text_marks_1.setText("StudentMarks : " + response.body().getArrestedDrugPer());
} else {
//unsuccessful response
}
} catch (Exception e) {
Log.d("onResponse", "There is an error");
e.printStackTrace();
}
}
#Override
public void onFailure(Call<Student> call, Throwable t) {
Log.d("onFailure", t.toString());
}
});
}
and in my logcat is this, i can see the json data but on my response.body returns null.
logcat
What should I do?
You are getting a response but there is issue in deserialization.
Reason being the Call<Student> is not the type it will be serialized to becuase you are getting a List of Students(JSONArray).
add this class
MyResponse
public class MyResponse {
#SerializedName("data")
#Expose
private List<Student> data = null;
public List<Student> getData() {
return data;
}
public void setData(List<Student> data) {
this.data = data;
}
}
and change your call to:
#GET("getJson")
Call<MyResponse> getStudentDetails();
Now you will get response body
and how to retrive?
List<Student> students = response.body().getData();
This will do..:)

ServiceStack empty metadata

Seeing a strange problem, getting empty metata pages for xml,json and jvs.
Using the following command line app. How does one debug these issues?
namespace ConsoleApplication2
{
public struct NativeUser
{
public int login;
public string group;
public string name;
}
[DataContract]
public class User
{
private NativeUser _native;
public User() { }
public User(NativeUser native)
{
_native = native;
}
public static implicit operator NativeUser(User user)
{
return user._native;
}
public static implicit operator User(NativeUser native)
{
return new User(native);
}
// ReSharper disable InconsistentNaming
[DataMember]
public int login
{
get { return _native.login; }
set { _native.login = value; }
}
[DataMember]
public string group
{
get { return _native.group; }
set { _native.group = value; }
}
[DataMember]
public string name
{
get { return _native.name; }
set { _native.name = value; }
}
}
[Description("GET account, all or by list of groups or by list of logins")]
[Route("/accounts/{groups}", "GET")]
[Route("/accounts/{logins}", "GET")]
[Route("/accounts/", "GET")]
public class Accounts : IReturn<User[]>
{
public string[] groups { set; get; }
public int[] logins { set; get; }
public Accounts() { }
public Accounts(params int[] logins)
{
this.logins = logins;
}
public Accounts(params string[] groups)
{
this.groups = groups;
}
}
public class Host : AppHostHttpListenerBase
{
public Host() : base("Test",
typeof(Accounts).Assembly)
{
}
public override void Configure(Funq.Container container)
{
}
}
public class Servce : IService
{
public object Get(Accounts request)
{
return new List<User>(){new User(new NativeUser())};
}
}
class Program
{
static void Main(string[] args)
{
var host = new Host();
host.Init();
host.Start("http://+:12345/");
global::System.Console.ReadLine();
}
}
}
Nm, found the bug :
public class Accounts : IReturn<User[]>
needs to be
public class Accounts : IReturn<List<User>>
Another very note worthy thing: All DTO's and objects being passed back and fourth in the DTO's require an empty constructor in order for the metata data to be properly generated.
Not sure if this is by design or a bug

Resources