I am looking for best solution how to convert POJO or JSON to XML with all atttributes in correct places. For now, Jackson looks like the most convenient way. I am able to serialize POJO to XML without attributes.
POJO TestUser
public class TestUser extends JsonType
{
#JsonProperty("username")
private final String username;
#JsonProperty("fullname")
private final String fullname;
#JsonProperty("email")
private final String email;
#JsonProperty("enabled")
private final Boolean enabled;
#JsonCreator
public TestUser(
#JsonProperty("username") String username,
#JsonProperty("fullname") String fullname,
#JsonProperty("email") String email,
#JsonProperty("enabled") Boolean enabled)
{
this.username = username;
this.fullname = fullname;
this.email = email;
this.enabled = enabled;
}
#JsonGetter("username")
public String getUsername()
{
return username;
}
#JsonGetter("fullname")
public String getFullname()
{
return fullname;
}
#JsonGetter("email")
public String getEmail()
{
return email;
}
#JsonGetter("enabled")
public Boolean getEnabled()
{
return enabled;
}
}
}
Here is the code:
public void testJsonToXML() throws JsonParseException, JsonMappingException, IOException
{
String jsonInput = "{\"username\":\"FOO\",\"fullname\":\"FOO BAR\", \"email\":\"foobar#foobar.com\", \"enabled\":\"true\"}";
ObjectMapper jsonMapper = new ObjectMapper();
TestUser foo = jsonMapper.readValue(jsonInput, TestUser.class);
XmlMapper xmlMapper = new XmlMapper();
System.out.println(xmlMapper.writer().with(SerializationFeature.WRAP_ROOT_VALUE).withRootName("product").writeValueAsString(foo));
}
And now it returns this
<TestUser xmlns="">
<product>
<username>FOO</username>
<fullname>FOO BAR</fullname>
<email>foobar#foobar.com</email>
<enabled>true</enabled>
</product>
</TestUser>
Which is nice, but I need variable enabled to be attribute of username and then I need to add xmlns and xsi attributes to the root element so the XML result looks like this
<TestUser xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="testUser.xsd">
<product>
<username enabled="true">FOO</username>
<fullname>FOO BAR</fullname>
<email>foobar#foobar.com</email>
</product>
</TestUser>
I found some examples using #JacksonXmlProperty but it only adds the attribute to the root element.
Thanks for help
Interesting problem: injection of additional data. There is no functionality for doing that currently; but I think it'd be possible to add, say, a new attribute in #JsonRootName (schema=URL?), that would allow addition of a schema mapping or mappings?
I went ahead and filed this:
https://github.com/FasterXML/jackson-dataformat-xml/issues/90
to add something that should work; feel free to add comments, suggestions.
Related
My entity class
public class User {
String name;
String userName;
String password;
String[] roles;
static class ROLES {
static String ADMIN="ADMINISTRATOR";
static String USER="USER";
}
public User(){
}
public User(String name, String userName, String password, String... roles) {
this.name = name;
this.userName = userName;
this.password = password;
this.roles = roles;
}
}
Format of the properties file
user[0].name=Sujal Mandal
user[0].userName=sujal12
user[0].password=sujal123
user[0].roles=ADMIN,USER,SUPER_USER
user[1].name=Busra Ercelik
user[1].userName=busra12
user[1].password=busra123
user[1].roles=USER
I would like to write an util class which will read the properties file & return me the objects of Users
What would be the best way of doing this in Java/Spring boot enviornment?
The simplest solution is shown below where in you need to use #ConfigurationProperties:
#Component
#ConfigurationProperties("myproject")
public class UsersPopulator {
private List<User> users;//all users will be populated from application.properties
//add getter method
}
Your application.properties file looks like the below:
myproject.users[0].name=Sujal Mandal
myproject.users[0].userName=sujal12
myproject.users[0].password=sujal123
myproject.users[0].roles=ADMIN,USER,SUPER USER
myproject.users[1].name=Busra Ercelik
myproject.users[1].userName=busra12
myproject.users[1].password=busra123
myproject.users[1].roles=USER
You need to ensure that #EnableConfigurationProperties is added to the launcher class file.
This is My JSON String : "{'userName' : 'Bachooo'}"
Converting JSON String to LoginVO logic is:
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
LoginVO loginFrom = gson.fromJson(jsonInString, LoginVO.class);
System.out.println("userName " + loginFrom.getUserName()); // output null
My LoginVO.class is:
public class LoginVO {
private String userName;
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;
}
}
Note I am using jdk 1.8.0_92
Output of loginForm.getUserName() is NULL instead of "Bachooo" any idea about this issue?
Since you are setting excludeFieldsWithoutExposeAnnotation() configuration on the GsonBuilder you must put #Expose annotation on those fields you want to serialize/deserialize.
So in order for excludeFieldsWithoutExposeAnnotation() to serialize/deserialize your fields you must add that annotation:
#Expose
private String userName;
#Expose
private String password;
Or, you could remove excludeFieldsWithoutExposeAnnotation() from the GsonBuilder.
Adding what resolved this for me.
So in my API following gson implementation was getting used:
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
I had to use the same implementation in my test, before which gson was failing to parse attributes.
So in essence check how your gson is configured in api/handler, and use same configuration in your test.
Try like this, please. Here is the example class:
class AngilinaJoile {
private String name;
// setter
// getter
}
And here is how you deserialize it with Gson:
Gson gson = new Gson();
String jsonInString = "{'name' : 'kumaresan perumal'}";
AngilinaJoile angel = gson.fromJson(jsonInString, AngilinaJoile.class);
i have problem with my jaxb EclipseLink implementation.
Let's assume I have the following Entity ...
#XmlRootElement(name = GenericConfigEntity.XML_ROOT_TAG)
public class GenericConfigEntity {
private String name;
private String data;
private String version;
private String date;
private String template;
#XmlAttribute(name = GenericConfigEntity.XML_NAME)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#XmlElement(name = GenericConfigEntity.XML_DATA)
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
#XmlAttribute(name = GenericConfigEntity.XML_VERSION)
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
#XmlAttribute(name = GenericConfigEntity.XML_DATE)
public String getDate() {
return date;
}
public String getTemplate() {
return template;
}
public void setTemplate(String template) {
this.template = template;
}
}
The string 'template' contains xml data already let's say someting like this (in my real context it is a lot more and I do not want to create the entities for this).
<Prozess name="xx" test="1">
<Debug system="test" />
</Prozess>
Now my question is if there is a way to integrate the template string into the marshalling process that someting like this is generated
<conf name="xx" version="x" datum="xx">
<Prozess name="xx" test="1">
<Debug system="test" />
</Prozess>
<Data>
TextTextText
</Data>
</conf>
It is no solution to wrap the template in an tag because i am restricted to this layout.
Also #XmlValue is no solution because I get an exception "all other elements have to be an attribute because one is marked as xmlvalue".
I haven't used this myself yet, but I reckon you could use the #XmlAnyElement in conjunction with a DomHandler to implement such a mapping. You can find a helpful example in the blog of MOXy's lead programmer here.
I think you'd still have to make sure that the XML content in your template field has at least an opening and a closing tag, which serve to identify the DOM element during (un)marshalling. That tag may be arbitrary as required by you. I guess you could just look for the first tag appearing in the string and try to match it against the end of the string.
I have an xml. I want to convert to object , xstream convert well all tags except one of them it gives null.
Any idea about this problem ?
xml:
<person>
<name>nnn</name>
<age>aaa</age>
<address>
<city>ccc</city>
<countryco</country>
</address>
</person>
Code java
XStream _xstream = new XStream();
_xstream.setMode(XStream.NO_REFERENCES);
_xstream.aliasType("person", PersonType.class);
_xstream.aliasType("address", PersonType.class);
_xstream.aliasField("city", AddressType.class, "city");
_xstream.aliasField("country", AddressType.class, "country");
When I inspect the object person , all variables are ok , but address is always null
i tried this :
_xstream.aliasType("person", PersonType.class);
_xstream.aliasType("address", AddressType.class);
_xstream.aliasField("city", AddressType.class, "city");
_xstream.aliasField("country", AddressType.class, "country");
but still don't work !
In this case the usage of alias are redundant. XStream will convert the names of the fields automaticly.
How ever you adress seems to be an nested type. You are using the same type for two aliases:
_xstream.aliasType("person", PersonType.class);
_xstream.aliasType("address", PersonType.class);
it should be
_xstream.aliasType("address", AddressType.class);
for adress alias.
Java Code:
#XStreamAlias("person")
public class Person {
#XStreamAlias("name")
private String Name;
#XStreamAlias("age")
private long Age;
#XStreamImplicit(itemFieldName = "address")
private List addresses = new ArrayList();
}
#XStreamAlias("adress")
public class Address{
#XStreamAlias("city")
private String City;
#XStreamAlias("country")
private String Country;
}
Main Code:
FileReader reader = new FileReader("file.xml"); // load file
XStream xstream = new XStream();
xstream.processAnnotations(Person.class);
xstream.processAnnotations(Address.class);
Person person = (Person) xstream.fromXML(reader);
I believe address would be a reference of object Address in your class Person. If so then you need to do like this:
Person.java
public class Person{
private String name;
private int age;
private Address address;
public String getName(){
return name;
}
public int getAge(){
return age;}
public String getcity(){
return address.getCity();
}
public String getCountry(){
return address.getCountry();
}
}
Address.java
public class Address {
private String city;
private String country;
public String getCity(){
return city;
}
public String getCountry(){
return country;
}
}
JAVA CODE
FileReader xmlReader = new FileReader("file.xml"); // load file
XStream stream = new XStream(new StaxDriver());
stream.alias("person",Person.class);//Since in your xml file `person` is tag
Person person = (Person) stream.fromXML(xmlReader);
System.out.println("Name:"+person.getName()+"\nAge:"+person.getAge()+
"\nCity:"+person.getCity()+"\nCountry:"+person.getCountry();
I have Pojo object, with getAsJson function to return Json string for this object.
I use JsonProperty to define json properties in this object.
Use writeValueAsString of ObjectMapper to write json string for this object.
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
#JsonIgnoreProperties(ignoreUnknown=true)
public class LogLikeArticleDetail extends BaseObject {
private static final long serialVersionUID = -2018373118257019033L;
#JsonProperty("LikeArticleGUId")
private String likeArticleGUId;
#JsonProperty("UserId")
private String userID;
#JsonProperty("UserName")
private String userName;
#JsonProperty("IP")
private String ip;
#JsonProperty("OS")
private String os;
#JsonProperty("UserAgent")
private String userAgent;
#JsonProperty("WebsiteCode")
private String websiteCode;
#JsonProperty("ArticleId")
private String articleID;
#JsonProperty("ATitle")
private String aTitle;
#JsonProperty("CateAlias")
private String cateAlias;
#JsonProperty("LikeStatus")
private String likeStatus;
#JsonProperty("TimeStamp")
private Date timeStamp;
//get, set....
//....
#JsonIgnore
public String getAsJSON() throws JsonGenerationException, JsonMappingException, IOException{
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(this) ;
}
}
Now, i get result
public static void main(String[] args) throws JsonGenerationException, JsonMappingException, IOException {
Calendar calendar = Calendar.getInstance();
LogLikeArticleDetail logLikeArticle = new LogLikeArticleDetail("1","2","3","4","5","6","7","8","what thing \"nothing\" show","10","11",calendar.getTime());
System.out.println(logLikeArticle.getAsJSON());
}
But the result's duplicated properties:
{"LikeArticleGUId":"1","UserId":"2","UserName":"3","IP":"4","OS":"5","UserAgent":"6","WebsiteCode":"7","ArticleId":"8","ATitle":"what thing \"nothing\" show","CateAlias":"10","LikeStatus":"11","TimeStamp":1352256727062,"_likeArticleGUId":"1","websiteCode":"7","likeStatus":"11","userID":"2","userName":"3","ip":"4","os":"5","userAgent":"6","articleID":"8","aTitle":"what thing \"nothing\" show","cateAlias":"10","timeStamp":1352256727062}
Show me what's occur in this problem ?
So i do follow:
how to specify jackson to only use fields - preferably globally
I add
#JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)
before
public class LogLikeArticleDetail extends BaseObject
and the result that i want.
So can another solve that in getAsJson() function like:
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibilityChecker(mapper.getSerializationConfig().getDefaultVisibilityChecker()
.withFieldVisibility(JsonAutoDetect.Visibility.ANY)
.withGetterVisibility(JsonAutoDetect.Visibility.NONE)
.withSetterVisibility(JsonAutoDetect.Visibility.NONE)
.withCreatorVisibility(JsonAutoDetect.Visibility.NONE));
return mapper.writeValueAsString(this) ;
Thanks for #Sean Carpenter 's question and #kmb385 answer in link above.
You can also do this per POJO using annotations. Add this string to the top of your class you'd like no auto detection on:
#JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY,
getterVisibility=JsonAutoDetect.Visibility.NONE,
setterVisibility=JsonAutoDetect.Visibility.NONE,
creatorVisibility=JsonAutoDetect.Visibility.NONE)
For example:
#JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY, getterVisibility=JsonAutoDetect.Visibility.NONE,
setterVisibility=JsonAutoDetect.Visibility.NONE, creatorVisibility=JsonAutoDetect.Visibility.NONE)
class Play {
#JsonProperty("Name")
private String name;
#JsonProperty("NickName")
private String nickName;
public Play(){
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
}
This will return the properties I've defined and not auto-detect the field names and add them to my returned JSON result.
We can also use the #JsonProperty("Name") annotation directly on the getters to avoid duplication.
It is actually not an issue. So, over here what happened was Jackson library was unable to match those fields automatically (there is no assumption of case unification), so you end up with twice the properties you expect.
The simple fix for this issue is to just add annotations to either getters/setters (either is fine.)
#JsonProperty("UserName")
public String getUserName() {
return this.userName;
}
This issue was also raised in Jackson Github repo. You can find the answer in the following link.
https://github.com/FasterXML/jackson-databind/issues/1609