i using follow code:
#XStreamAlias("ListOfMBDO")
public class XMLListOfMBDO {
#XStreamImplicit(itemFieldName = "MBDO")
public List<ModifyBetriebsortDataObject> items = new LinkedList<ModifyBetriebsortDataObject>();
}
public class ModifyBetriebsortDataObject {
#XStreamAlias("PK")
public Integer pk;
#XStreamAlias("NAME")
public String name;
public ModifyBetriebsortDataObject(final Integer pk, final String name) {
this.pk = pk;
this.name = name;
}
}
public void loadThis() {
final String test = "<ListOfMBDO><MBDO><PK>123456</PK><NAME>Test</NAME></MBDO></ListOfMBDO>";
final XStream _xStream = new XStream(new DomDriver());
_xStream.processAnnotations(XMLListOfMBDO.class);
_xStream.processAnnotations(ModifyBetriebsortDataObject.class);
final XMLListOfMBDO testList = (XMLListOfMBDO) _xStream.fromXML(test);
}
The Serializationto XML works fine. But the deserialization throws an
com.thoughtworks.xstream.mapper.CannotResolveClassException: ....data.XMLListOfMBDO : ....data.XMLListOfMBDO
at com.thoughtworks.xstream.mapper.DefaultMapper.realClass(DefaultMapper.java:68)
at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38)
at com.thoughtworks.xstream.mapper.DynamicProxyMapper.realClass(DynamicProxyMapper.java:71)
...
Why?
You can try solving deserialization error by adding
_xStream.alias("ListOfMBDO", XMLListOfMBDO.class);
Related
Something is wrong and application crashes. I am trying to parse xml text into java classes, I'm using XStream library. Code crashes after I use method fromXML. My code:
XML file looks like this:
<FilesManifest>
<Group>
<HeaderName>Pirmas hdr</HeaderName>
<Type>theory</Type>
<Piece>
<FileName>11.txt</FileName>
<HeadLine>hi1</HeadLine>
</Piece>
<Piece>
<FileName>22.txt</FileName>
<HeadLine>hi2</HeadLine>
</Piece>
</Group>
<Group>
<HeaderName>antras hdr</HeaderName>
<Type>theory</Type>
<Piece>
<FileName>33.txt</FileName>
<HeadLine>hi3</HeadLine>
</Piece>
<Piece>
<FileName>44.txt</FileName>
<HeadLine>hi4</HeadLine>
</Piece>
</Group>
<Group>
<HeaderName>tracias hdr</HeaderName>
<Type>test</Type>
<Piece>
<FileName>55.txt</FileName>
<HeadLine>hi5</HeadLine>
</Piece>
<Piece>
<FileName>66.txt</FileName>
<HeadLine>hi6</HeadLine>
</Piece>
</Group>
</FilesManifest>
My main function code:
String fileText = ReadFile();
XStream xstream = new XStream();
xstream.alias("FilesManifest", MyFileManager.class);
xstream.alias("Group", MyGroup.class);
xstream.alias("Piece", MyPiece.class);
MyFileManager data = (MyFileManager)xstream.fromXML(fileText);
And classes for xml parsing:
public class MyFileManager {
public List<MyGroup> getGroups() {
return groups;
}
public void setGroups(List<MyGroup> groups) {
this.groups = groups;
}
#XStreamImplicit(itemFieldName = "group")
private List<MyGroup> groups = new ArrayList<MyGroup>();
}
public class MyGroup {
private String headerName;
private String type;
#XStreamImplicit(itemFieldName = "piece")
private List<MyPiece> pieces = new ArrayList<MyPiece>();
public List<MyPiece> getPieces() {
return pieces;
}
public void setPieces(List<MyPiece> pieces) {
this.pieces = pieces;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getHeaderName() {
return headerName;
}
public void setHeaderName(String headerName) {
this.headerName = headerName;
}
}
public class MyPiece {
private String fileName;
private String headLine;
public String getHeadLine() {
return headLine;
}
public void setHeadLine(String headLine) {
this.headLine = headLine;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
}
So can you advice me that code would work correctly? Maybe there is other way to parse?
I could make your code work by fixing 2 main issues:
Your mapping is incomplete and not correct because you seem to forget that XML is case-sensitive which means that for example #XStreamImplicit(itemFieldName = "group") should be #XStreamImplicit(itemFieldName = "Group") and all the fields must be annotated with #XStreamAlias to provide an alias with the first character in capital.
You did not call processAnnotations(Class type) such that your annotations are not processed.
So at the end your code should be something like that:
Your POJOs:
public class MyFileManager {
...
#XStreamImplicit(itemFieldName = "Group")
private List<MyGroup> groups = new ArrayList<>();
}
public class MyGroup {
#XStreamAlias("HeaderName")
private String headerName;
#XStreamAlias("Type")
private String type;
#XStreamImplicit(itemFieldName = "Piece")
private List<MyPiece> pieces = new ArrayList<>();
...
}
public class MyPiece {
#XStreamAlias("FileName")
private String fileName;
#XStreamAlias("HeadLine")
private String headLine;
...
}
Your main function code:
...
// Process the provided annotations
xstream.processAnnotations(MyFileManager.class);
MyFileManager data = (MyFileManager)xstream.fromXML(fileText);
I am experiencing strange behavior. I am using hibernate. I have two tables.
#Entity
public class Nemocnica implements java.io.Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="N_ID")
private BigDecimal NId;
#Column(name="adresa")
private String adresa;
#OneToMany
private Set sanitkas = new HashSet(0);
public Nemocnica() {
}
public Nemocnica( String adresa) {
this.NId = NId;
}
public Nemocnica(BigDecimal NId, String adresa) {
this.NId = NId;
this.adresa = adresa;
}
public Nemocnica(BigDecimal NId, String adresa, Set sanitkas) {
this.NId = NId;
this.adresa = adresa;
this.sanitkas = sanitkas;
}
public BigDecimal getNId() {
return this.NId;
}
public void setNId(BigDecimal NId) {
this.NId = NId;
}
public String getAdresa() {
return this.adresa;
}
public void setAdresa(String adresa) {
this.adresa = adresa;
}
public Set getSanitkas() {
return this.sanitkas;
}
public void setSanitkas(Set sanitkas) {
this.sanitkas = sanitkas;
}
}
and second
#Entity
public class Sanitka implements java.io.Serializable {
private BigDecimal sanitkaId;
private transient Nemocnica nemocnica;
private BigDecimal kapacita;
#ManyToOne
#JoinColumn(name="nemocnica_n_id")
private Set sanitaris = new HashSet(0);
public Sanitka() {
}
public Sanitka(BigDecimal sanitkaId, Nemocnica nemocnica, BigDecimal kapacita) {
this.sanitkaId = sanitkaId;
this.nemocnica = nemocnica;
this.kapacita = kapacita;
}
public Sanitka(BigDecimal sanitkaId, Nemocnica nemocnica, BigDecimal kapacita, Set sanitaris) {
this.sanitkaId = sanitkaId;
this.nemocnica = nemocnica;
this.kapacita = kapacita;
this.sanitaris = sanitaris;
}
public BigDecimal getSanitkaId() {
return this.sanitkaId;
}
public void setSanitkaId(BigDecimal sanitkaId) {
this.sanitkaId = sanitkaId;
}
#ManyToOne(cascade=CascadeType.ALL)
public Nemocnica getNemocnica() {
return this.nemocnica;
}
public void setNemocnica(Nemocnica nemocnica) {
this.nemocnica = nemocnica;
}
public BigDecimal getKapacita() {
return this.kapacita;
}
public void setKapacita(BigDecimal kapacita) {
this.kapacita = kapacita;
}
public Set getSanitaris() {
return this.sanitaris;
}
public void setSanitaris(Set sanitaris) {
this.sanitaris = sanitaris;
}
}
And routes that mannipulate with them.
nemocnicaRoute:
#Path("nemocnica")
public class nemocnicaRoute {
// private static final helper db = new helper();
#GET
#Path("all")
#Produces(MediaType.APPLICATION_JSON)
public String getName(){
List<Nemocnica> l = db.helper.getNemocnicas();
GsonBuilder builder = new GsonBuilder();
Gson gson = builder.create();
//System.out.println( json );
//return l.toString();
return gson.toJson(l);
}
// another methods
}
sanitkaRoute
#Path("sanitka")
public class sanitkaRoute {
//private static final helper db = new helper();
#GET
#Path("all")
#Produces("text/plain")
public String getName(){
List<Sanitka> l = db.helper.getSanitkas();
GsonBuilder builder = new GsonBuilder();
Gson gson = builder.create();
//System.out.println( json );
//return l.toString();
return gson.toJson(l);
}
// another methods
}
I am using these two getName() methods to retrieve all data from said tables.
This cause strange behavior , if i invoke get request on nemocnicaRoute first , it works very well as it should.
However when i invoke get requet on sanitkaRoute first , it works but after that when i want to invoke get request on nemocniceRoute it throws
java.lang.UnsupportedOperationException: Attempted to serialize
java.lang.Class: org.hibernate.proxy.HibernateProxy. Forgot to
register a type adapter?
Which confuses me , bcs this does not happen when i invoke getRequest on nemocnicaRoute first.
How could i fix this strange behavior?
All help appreciated
I create an java class:
public class ReturnObj {
private String returncode;
private String returndesc;
private Pkg pkg;
public String getReturncode() {
return returncode;
}
public void setReturncode(String returncode) {
this.returncode = returncode;
}
public String getReturndesc() {
return returndesc;
}
public void setReturndesc(String returndesc) {
this.returndesc = returndesc;
}
}
and other class:
public class Pkg {
private String packagecode;
private String cycle;
private String price;
private String desc;
public String getPackagecode() {
return packagecode;
}
public void setPackagecode(String packagecode) {
this.packagecode = packagecode;
}
public String getCycle() {
return cycle;
}
public void setCycle(String cycle) {
this.cycle = cycle;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
And I Want to convert object ReturnObj to this XML
<return>
<returncode>1</returncode>
<returndesc>DANG_KY_THANH_CONG</returndesc>
<package>
<packagecode>BD30</packagecode>
<cycle>1</cycle>
<price>15000</price>
<desc> BD30</desc>
</package>
</return>
So how do I serialize an attribute pkg to package in XML? Because Java doesn't allow to name variable as an keyword anh package is an keyword in Java !
You can use JAXB marshling in your class it will convert the object to XML, here is link to help you JAXB Marshling
Try xstream
XStream xstream = new XStream();
xstream.alias("package", Pkg.class);
String xml = xstream.toXML(myReturnObj);
You can use JAXB API that comes with java for converting java object to XML.
Below is the code that will solve your requirement.
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "return")
public class ReturnObj {
private String returncode;
private String returndesc;
private Pkg pkg;
public Pkg getPkg() {
return pkg;
}
#XmlElement(name = "package")
public void setPkg(Pkg pkg) {
this.pkg = pkg;
}
public String getReturncode() {
return returncode;
}
#XmlElement(name = "returncode")
public void setReturncode(String returncode) {
this.returncode = returncode;
}
public String getReturndesc() {
return returndesc;
}
#XmlElement(name = "returndesc")
public void setReturndesc(String returndesc) {
this.returndesc = returndesc;
}
}
#XmlRootElement
public class Pkg {
private String packagecode;
private String cycle;
private String price;
private String desc;
public String getPackagecode() {
return packagecode;
}
#XmlElement(name="packagecode")
public void setPackagecode(String packagecode) {
this.packagecode = packagecode;
}
public String getCycle() {
return cycle;
}
#XmlElement(name="cycle")
public void setCycle(String cycle) {
this.cycle = cycle;
}
public String getPrice() {
return price;
}
#XmlElement(name="price")
public void setPrice(String price) {
this.price = price;
}
public String getDesc() {
return desc;
}
#XmlElement
public void setDesc(String desc) {
this.desc = desc;
}
}
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
public class JAXBExample {
private static final String FILE_NAME = "C:\\ru\\jaxb-returnObj.xml";
public static void main(String[] args) {
ReturnObj returnObj = new ReturnObj();
returnObj.setReturncode("1");
returnObj.setReturndesc("DANG_KY_THANH_CONG");
Pkg pkg = new Pkg();
pkg.setCycle("1");
pkg.setPrice("15000");
pkg.setDesc("BD30");
returnObj.setPkg(pkg);
jaxbObjectToXML(returnObj);
}
private static void jaxbObjectToXML(ReturnObj emp) {
try {
JAXBContext context = JAXBContext.newInstance(ReturnObj.class);
Marshaller m = context.createMarshaller();
// for pretty-print XML in JAXB
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
// Write to System.out, this will print the xml on console
m.marshal(emp, System.out);
// Write to File
m.marshal(emp, new File(FILE_NAME));
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
Explanation:
#XmlRootElement: This is a must have annotation for the Object to be used in JAXB. It defines the root element for the XML content.
#XmlElement: This will create the element. If you want to give some other name to the xml element when converting java object to xml then you can pass name attribute to the #XmlElement Example:
#XmlElement(name = "package")
Execute above code to see the desired output.
Happy Coding.
I would like to map a field with nested collection using Orika library. My field in class is defined as:
private final List<List<Pojo>> list = new LinkedList<List<Pojo>>();
Pojo is a simple POJO class. Unfortunately I've got a MappingException caused by NullPointerException in Orika's internal logic.
Did I do something in wrong way? Maybe I need to use Custom Mapping feature?
EDIT:
Here is my code:
public class Pojo {
private int field;
public int getField() {
return field;
}
public void setField(final int field) {
this.field = field;
}
}
public class Source {
private final List> list = new LinkedList>();
public List<List<Pojo>> getList() {
return list;
}
}
public class Destination {
private final List> listDest = new LinkedList>();
public List<List<Pojo>> getListDest() {
return listDest;
}
}
public class Main {
public static void main(final String[] args) {
final MapperFactory factory = new DefaultMapperFactory.Builder().build();
factory.classMap(Source.class, Destination.class).field("list", "listDest").byDefault().register();
final Source src = new Source();
final LinkedList<Pojo> nestedList = new LinkedList<Pojo>();
final Pojo pojo = new Pojo();
pojo.setField(8978);
nestedList.add(pojo);
src.getList().add(nestedList);
final MapperFacade facade = factory.getMapperFacade();
final Destination dest = facade.map(src, Destination.class);
System.out.println(dest.getListDest().get(0).get(0).getField());
}
}
Execution above code results this Exception:
Exception in thread "main" ma.glasnost.orika.MappingException: Error encountered while mapping for the following inputs:
rawSource=com.bbh.nested.Source#39185ce6
sourceClass=class com.bbh.nested.Source
destinationClass=class com.bbh.nested.Destination
You can see this Example:
public class ShopEntity {
private Long id;
private String name;
private String logo;
private String url;
private ProductCategory mainCategory;
private Set<ShopRel> shopRels = new HashSet<>(0);
private Account account;
// Assume getter/setter
}
public class ProductCategory extends BaseEntity {
private Long id;
private String name;
// Assume getter/setter
}
public class ShopRel {
private Long id;
private SaleChannel saleChannel;
private Boolean enabled;
// Assume getter/setter
}
public class SaleChannel {
private Long id;
private String name;
private String image;
private String description;
private Boolean active;
// Assume getter/setter
}
public class ShopDto {
private Long id;
private String name;
private String logo;
private String url;
private Long mainCategory;
private Set<ShopRelDto> shopRelDtos = new HashSet<ShopRelDto>();
// Assume getter/setter
}
public class ShopRelDto {
private Long channelId;
private String name;
private Boolean enabled;
// Assume getter/setter
}
public class MapperUtils {
private static final MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
private static final MapperFacade mapper = mapperFactory.getMapperFacade();
static {
mapperFactory.classMap(ShopEntity.class, ShopDto.class)
.field("mainCategory.id", "mainCategory")
.fieldMap("shopRels", "shopRelDtos").aElementType(ShopRel.class).bElementType(ShopRelDto.class).add()
.register();
mapperFactory.classMap(ShopRel.class, ShopRelDto.class)
.field("saleChannel.id", "channelId")
.field("saleChannel.name", "name")
.field("enabled", "enabled")
.register();
}
public static final void map(Object source, Object distance) {
mapper.map(source, distance);
}
public static final <T> T map(Object source, Class<T> destinationClass){
return mapper.map(source, destinationClass);
}
public static void main(String[] args) {
ShopEntity shop = new ShopEntity();
shop.setId(1L);
shop.setName("ABC");
ProductCategory productCategory =new ProductCategory();
productCategory.setId(10L);
shop.setMainCategory(productCategory);
Set<ShopRel> shopRels = new HashSet<>(0);
ShopSaleChannelRel channelRel = new ShopSaleChannelRel();
channelRel.setId(1L);
channelRel.setEnabled(true);
SaleChannel saleChannel = new SaleChannel();
saleChannel.setId(1L);
saleChannel.setName("Channel1");
channelRel.setSaleChannel(saleChannel);
shopRels.add(channelRel);
shop.setShopRels(shopRels);
ShopDto shopDto = map(shop, ShopDto.class);
System.out.println(shopDto);
}
}
It may need a custom mapping via customize if there is lot of cases like this you can extend Orika via Specifications to support this use case
I am using jackson 2.2 annotation #JsonProperty with required set to true. While deserializing json file which doesn't contain that property via ObjectMapper readValue() method no exception is being thrown.
Is it supposed to work in a different way or did I missed something?
My dto class:
public class User {
public enum Gender {MALE, FEMALE}
;
public static class Name {
private String _first, _last;
public String getFirst() {
return _first;
}
public String getLast() {
return _last;
}
public void setFirst(String s) {
_first = s;
}
public void setLast(String s) {
_last = s;
}
}
private Gender _gender;
private Name _name;
private boolean _isVerified;
private byte[] _userImage;
#JsonProperty(value ="NAAME",required = true)
public Name getName() {
return _name;
}
#JsonProperty("VERIFIED")
public boolean isVerified() {
return _isVerified;
}
#JsonProperty("GENDER")
public Gender getGender() {
return _gender;
}
#JsonProperty("IMG")
public byte[] getUserImage() {
return _userImage;
}
#JsonProperty(value ="NAAME",required = true)
public void setName(Name n) {
_name = n;
}
#JsonProperty("VERIFIED")
public void setVerified(boolean b) {
_isVerified = b;
}
#JsonProperty("GENDER")
public void setGender(Gender g) {
_gender = g;
}
#JsonProperty("IMG")
public void setUserImage(byte[] b) {
_userImage = b;
}
}
This is how do I deserialize the class:
public class Serializer {
private ObjectMapper mapper;
public Serializer() {
mapper = new ObjectMapper();
SimpleModule sm = new SimpleModule("PIF deserialization");
mapper.registerModule(sm);
}
public void writeUser(File filename, User user) throws IOException {
mapper.writeValue(filename, user);
}
public User readUser(File filename) throws IOException {
return mapper.readValue(filename, User.class);
}
}
This is how it is actually called:
Serializer serializer = new Serializer();
User result = serializer.readUser(new File("user.json"));
Actuall json looks like:
{"GENDER":"FEMALE","VERIFIED":true,"IMG":"AQ8="}
I would expect that since _name is not specified in json file and is required that the exception will be thrown.
With Jackson 2.6 you can use required, however you have to do it using JsonCreator
For example:
public class MyClass {
#JsonCreator
public MyClass(#JsonProperty(value = "x", required = true) Integer x, #JsonProperty(value = "value_y", required = true) Integer y) {
this.x = x;
this.y = y;
}
private Integer x;
private Integer y;
}
If x or y are not present an exception will be thrown when trying to deserialize it.
As per Jackson annotations javadocs: "Note that as of 2.0, this property is NOT used by BeanDeserializer: support is expected to be added for a later minor version."
That is: no validation is performed using this settings. It is only (currently) used for generating JSON Schema, or by custom code.