Dozer, how to map from java.util.Map to complex type? - getter

I'd like to map from a java.util.Map to a complex type, let's call it Abc.
<mapping>
<class-a>java.util.Map</class-a>
<class-b bean-factory="xyz.AbcBeanFactory" factory-bean-id="AbcBeanFactory">
xyz.Abc
</class-b>
<field>
<a>Name</a>
<b>companyName</b>
</field>
</mapping>
With that I get this error (which is comprehensible):
org.dozer.MappingException: No read or write method found for field (Name) in class (interface java.util.Map)
Ok, how do I map from a java.util.Map that has an entry with the key 'Name'? Do I have to create a wrapper object that holds that java.util.Map and provide getters/setters for each entry in that map that I want to map?

You can find details for mapping a Map in the Dozer documentation. You need to provide a key not a plain field. Here is an example:
Class Abc:
package com.test;
public class Abc {
private String companyName;
private String companyAddress;
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
public String getCompanyAddress() {
return companyAddress;
}
public void setCompanyAddress(String companyAddress) {
this.companyAddress = companyAddress;
}
}
Mapping file:
<mapping>
<class-a>java.util.Map</class-a>
<class-b>com.test.Abc</class-b>
<field>
<a key="name">this</a>
<b>companyName</b>
</field>
<field>
<a key="address">this</a>
<b>companyAddress</b>
</field>
</mapping>
Test code:
Map<String, String> map = new HashMap<String, String>();
map.put("name", "Company Inc.");
map.put("address", "XYZ Commercial Street");
Abc destObject = dozerMapper.map(map, Abc.class);

Related

How to use jaxb customization to change variable class

I try this:
<jxb:bindings node="xsd:element[#name='CustomList']">
<jxb:class name="java.util.List" />
</jxb:bindings>
but generated class look like:
#XmlElementRef(name = "CustomList", namespace = "urn:org:MyXsd:v1", type = JavaUtilList.class)
protected JAXBElement<?> customList;
This configuration needed for change class name of your "CustomList".
If you want change type you should use an XMLAdapter
<jxb:javaType name="java.util.Date" printMethod="com.xsd.DateTimeAdapter.printDateTime" parseMethod="com.xsd.DateTimeAdapter.parseDateTime" />
this is an example for DateTime...
public class DateTimeAdapter {
public static Date parseDateTime(String s) {
return DatatypeConverter.parseDateTime(s).getTime();
}
public static String printDateTime(Date dt) {
Calendar cal = new GregorianCalendar();
cal.setTime(dt);
return DatatypeConverter.printDateTime(cal);
}
}

JAXB and MOXy xml and json marshalling of generic list in jersey

I'm making a little restful client in Jersey, and i have come into a little trouble with supporting both XML and JSON marshaling.
The specific problem is about marshaling an object that holds a few properties, with a generic list included.
I have the following class annotated as followed:
#XmlRootElement
public class Block<E> {
private String headerText;
private List<E> elements;
public Block() {
}
#XmlElement
public String getHeaderText() {
return headerText;
}
#XmlElementWrapper(name = "elements")
#XmlElements({
#XmlElement(name = "element", type=Foo.class),
#XmlElement(name = "element", type=Bar.class)
})
public List<E> getElements() {
return elements;
}
}
The XML comes out fine:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<block>
<elements>
<element>
<id>1</id>
<title>Title01</title>
</element>
<element>
<id>2</id>>
<title>Title02</title>
</element>
</elements>
<headerText>FooBarHeader</headerText>
</block>
but the JSON is formatted like this
{
-elements : {
-element: [
- {
id : 1
title : "Title01"
}
- {
id : 2
title : "Title02"
}
]
}
headerText : "HeaderText"
}
I would of course be interested in not having the "element" property in my JSON output, and only have elements: [{}...{}]
I have already setup a ContextResolver that creates a MOXyConfig with properties for JSON_WRAPPER_AS_ARRAY_NAME - and this works fine for fx. A List<String> where I only have to declare the property with #XmlElement instead of #XmlElements.
Anyone who know of a solution of this problem?
JSON_WRAPPER_AS_ARRAY_NAME Property
The effect of the JSON_WRAPPER_AS_ARRAY_NAME property (see: http://blog.bdoughan.com/2013/03/binding-to-json-xml-handling-collections.html) depends on whether the item names are significant or not,
Insignificant Item Names
Below we know that each item in the collection is an instance of Foo or an instance of a subclass of Foo.
#XmlElementWrapper(name = "elements")
#XmlElement(name = "element")
public List<E> getElements() {
return elements;
}
Significant Item Names
In the case of #XmlElements the item name is significant since it tells us which class we need to instantiate on the unmarshal and can not be excluded.
#XmlElementWrapper(name = "elements")
#XmlElements({
#XmlElement(name = "foo", type=Foo.class),
#XmlElement(name = "bar", type=Bar.class)
})
public List<E> getElements() {
return elements;
}
What You Can Do
You can use MOXy's externmal mapping document to override the mapping for the elements property to the following:
#XmlElementWrapper(name = "elements")
#XmlElement(name = "foo")
public List<E> getElements() {
return elements;
}
Then the JAXBContext for XML will be based on the annotations, and the JAXBContext for JSON will be based on the annotatons and external mapping document.
For More Information
http://blog.bdoughan.com/2010/12/extending-jaxb-representing-annotations.html
http://blog.bdoughan.com/2011/09/mapping-objects-to-multiple-xml-schemas.html
Try registering another JSON Entity Provider, which will disable automatically Moxy for JSON marshalling (see the ref). If you enable e.g Jackson, you will have its own annotations to control how everything is marshalled.

convert String to Clob and vice versa in Hibernate

Suppose that I have a Class:
class EventTransaction {
.....
private Clob dataXML;
public Clob getDataXML() {
return dataXML;
}
public void setDataXML(Clob dataXML) {
this.dataXML = dataXML;
}
}
And Hibernate mapping xml:
<property name="dataXML" type="java.sql.Clob">
<column name="XML" sql-type="CLOB"/>
</property>
In java code, how to I convert a String to Clob and vice versa to save into to the database:
Ex: EventTransaction et = new EventTransaction();
String xml = "fdfsafafafa";
et.setDataXML(convertStringToClob(xml));
HibernateTemplate.saveOrUpdate(et);
Could you please help how to implement function convertStringToClob(String data);
Thanks,
Do this
#Column(name="XML")
#Lob
private String dataXML;
public String getDataXML() {
return dataXML;
}
public void setDataXML(String dataXML) {
this.dataXML = dataXML;
}
So there is no need to convert, and everything is done by Hibernate.
I showed it using annotations, the same thing can be done using .hbm.xml files.
Here is code I made a long time ago to convert a Clob to a String. It's meant to be used in a utility class.
public static String convertClobToString(Clob clob) throws IOException, SQLException {
Reader reader = clob.getCharacterStream();
int c = -1;
StringBuilder sb = new StringBuilder();
while((c = reader.read()) != -1) {
sb.append(((char)c));
}
return sb.toString();
}
And if I am not mistaken, to create a Clob you would do something like this
Clob myClobFile = new SerialClob("my string".toCharArray());
The limitation of 64000 characters is on the database side when you declare the XML column as VARCHAR (and not on Java String), so as long as your column XML is a CLOB, it should work.
Excerpt from working code:
Entity:
private String xml;
SQL (ORACLE):
XML CLOB,
Hibernate mapping:
<property name="xml" type="java.lang.String">
<column name="XML" length="999999" />
</property>
If you want to store the XML as a file, then you should rather use BLOBs as shown below :
Entity:
private byte[] xmlFile;
SQL (ORACLE):
XML BLOB,
Hibernate mapping:
<property name="xmlFile" type="java.io.File">
<column name="XML" />
</property>

JAXB XMLElementWrapper with attribute and value

Im trying to create an xml file which is similar looking to the below menetioned.
<message>
<header>
<params>
<param name="test1">value1</param>
<param name="test2">value2</param>
</params>
</header>
</message>
Can you please let me know, how to define the class hierarchy.
Thanks,
Prakash.A
#XmlRootElement
public class Message {
#XmlElement
private Header header;
}
public class Header {
#XmlElement(name="param")
#XmlElementWrapper
private Collection<Param> params;
}
public class Param {
#XmlAttribute
private String name;
#XmlValue
privaet String value;
}
getters/setters on your mark.
The best way to use #XmlElementWrapper.
shouled be denoted the name. like #XmlElementWrapper(name="params") though in this situation the default name is the properties's name.

Unmarshalling in JAXB

I have the following tester.xml file which contains some info about events.
<?xml version="1.0"?>
<resultset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<row>
<field name="esid">539661</field>
<field name="esname">Title 01</field>
<field name="eslink">http://www.some_event_link.com</field>
<field name="estext">Event description 01</field>
<field name="esinfo" xsi:nil="true" />
<field name="espicture_small">http://www.some_event_link.com/media/small_image.jpg</field>
<field name="espicture">http://www.some_event_link.com/media/some_image..gif</field>
<field name="espicture_big">http://www.some_event_link.com/media/big_image.jpg</field>
<field name="esbegin">2000-11-22</field>
<field name="esend">2011-12-15</field>
<field name="eventid">1379305</field>
<field name="eventname">Event name 01</field>
<field name="eventdate">2011-10-12</field>
<field name="eventtime">19:00:00</field>
<field name="eventlink">http://www.mysite.com/tickets.html</field>
<field name="eventvenue">Event venue 01</field>
</row>
<row>
<field name="esid">539636</field>
<field name="esname">Title 02</field>
<field name="eslink">http://www.some_event_link.com</field>
<field name="estext">Event description 02</field>
<field name="esinfo" xsi:nil="true" />
<field name="espicture_small">http://www.some_event_link.com/media/small_image.jpg</field>
<field name="espicture">http://www.some_event_link.com/media/some_image..gif</field>
<field name="espicture_big">http://www.some_event_link.com/media/big_image.jpg</field>
<field name="esbegin">2000-10-10</field>
<field name="esend">2011-11-01</field>
<field name="eventid">1379081</field>
<field name="eventname">Event name 01</field>
<field name="eventdate">2011-10-12</field>
<field name="eventtime">14:00:00</field>
<field name="eventlink">http://www.mysite.com/tickets.html</field>
<field name="eventvenue">Event venue 02</field>
</row>
Also I have my XML mapping classes as follows.
First is the class corresponding to the tag < resultset >
package com.wapice.xml.beans;
import java.util.ArrayList;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "resultset")
public class Resultset {
private ArrayList<Row> rowsList;
#XmlElement(required = true, name = "row")
public ArrayList<Row> getRowsList() {
return rowsList;
}
public void setRowsList(ArrayList<Row> rowsList) {
this.rowsList = rowsList;
}
}
Next is the class which corresponds to the tag < row >
package com.wapice.xml.beans;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlRootElement(name = "row")
#XmlType(propOrder = {"field"})
public class Row {
private String field;
#XmlElement(required = true, name = "field")
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
}
I tried to Unmarshall this xml into objects & print the field names & values on my console with the following code fragment.
try {
JAXBContext context = JAXBContext.newInstance(Resultset.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
Resultset resultSet = (Resultset)unmarshaller.unmarshal(new FileReader("tester.xml"));
for(Row row : resultSet.getRowsList()){
System.out.println("Field : " +row.getField());
}
}
catch (JAXBException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
But when I run the above code, it only prints the last field's value. The output is as follows.
Field : Event venue 01
Field : Event venue 02
Can someone please tell me what I'm doing wrong here & it would be much appreciated if someone could tell me how to print all my < field > along with their names & values.
Thanks in advance.
Asela.
You could introduce a Field object:
package com.wapice.xml.beans;
import javax.xml.bind.annotation.*;
public class Field {
#XmlAttribute name;
#XmlValue value;
}
And have the Row object hold onto a List of them:
package com.wapice.xml.beans;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlRootElement(name = "row")
#XmlType(propOrder = {"field"})
public class Row {
private List<Field> fields;
#XmlElement(required = true, name = "field")
public List<Field> getFields() {
return field;
}
public void setField(List<Field> fields) {
this.fields = fields;
}
}
For More Information
http://blog.bdoughan.com/2010/09/jaxb-collection-properties.html
http://blog.bdoughan.com/2011/06/jaxb-and-complex-types-with-simple.html
I managed to solve my issue with your post & it was really really helpful. Thank you so very much for that. However I had to do some modifications to get it working as my mapping classes were throwing the following exceptions.
com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
Class has two properties of the same name "rowsList"
this problem is related to the following location:
at public java.util.ArrayList com.wapice.xml.beans.Resultset.getRowsList()
at com.wapice.xml.beans.Resultset
this problem is related to the following location:
at private java.util.ArrayList com.wapice.xml.beans.Resultset.rowsList
at com.wapice.xml.beans.Resultset
Class has two properties of the same name "fieldsList"
this problem is related to the following location:
at public java.util.ArrayList com.wapice.xml.beans.Row.getFieldsList()
at com.wapice.xml.beans.Row
at private java.util.ArrayList com.wapice.xml.beans.Resultset.rowsList
at com.wapice.xml.beans.Resultset
this problem is related to the following location:
at private java.util.ArrayList com.wapice.xml.beans.Row.fieldsList
at com.wapice.xml.beans.Row
at private java.util.ArrayList com.wapice.xml.beans.Resultset.rowsList
at com.wapice.xml.beans.Resultset
Then I changed the names of the related getters/setters & it worked fine.
Following is how I changed it.
----------------
Class Resultset
----------------
#XmlElement(required = true, name = "row")
private ArrayList<Row> rowsList; // I kept the same name for this attribute
public ArrayList<Row> getRowsList() { // I changed this to getRows()
return rowsList;
}
public void setRowsList(ArrayList<Row> rowsList) { // I changed this to setRows()
this.rowsList = rowsList;
}
----------
Class Row
----------
#XmlElement(required = true, name = "field")
private ArrayList<Field> fieldsList; // I kept the same name for this attribute
public void setFieldsList(ArrayList<Field> fieldsList) { // I changed this to getFields()
this.fieldsList = fieldsList;
}
public ArrayList<Field> getFieldsList() { // I changed this to setFields()
return fieldsList;
}
Hope this helps someone else too.

Resources