In one of my projects i have a scenario where I'll be getting a xml file which contain sql parametrs, I have to read and construct Java object from that.
Below is sample xml
<parameters>
<sql id="1">
<city>Chennai</city>
<state>Tamilnadu</state>
</sql>
<sql id="2">
<city>Mumbai</city>
<state>Maharashtra</state>
</sql>
<sql id="3">
<city>Kolkata</city>
<state>West Bengal</state>
</sql>
</parameters>
I have to parse and get keys and values from these xml.
The Java object I'm expecting is
List<Map<String,String>> sqlParams;
Map sqlOne; sqlOne.put(city,Chennai); sqlOne.put(state,Tamilnadu); sqlParams.add(sqlOne);
Map sqlTwo; sqlTwo.put(city,Mumbai); sqlTwo.put(state,Maharashtra); sqlParams.add(sqlTwo);
and so on...
We use this List of map to run SQL.
Can some one suggest me a better way to do this.
To parse xml in java object, you can look into this documentation. http://docs.oracle.com/javase/8/docs/technotes/guides/xml/index.html
a very fast and convenient way of mapping XML is to use some existing library like Jackson.
It's usage is quite simple. You write a plain object class like the example:
public class Simple {
public int x = 1;
public int y = 2;
}
which maps a structure like this:
<Simple>
<x>1</x>
<y>2</y>
</Simple>
After installing the library you it's intuitive how to map your data structure.
I would recommend for your next projects to use a some project management tools (like maven or gradle) which allows you to easily import libraries for such tasks and to spend some time to investigate how database querying is implemented around. You might have a look to spring JPA just as a starting point.
Related
I have a couple of java classes that I want to convert to xml using jaxb. (I have no need to generate the classes based on the schema) I need to be able to map the class to different xml formats so I do not want to use annotations. From what I've seen my best option seems to be to use external xml bindings. So I wanted to know:
1) I am using eclipse. I am new to JAXB and I would like to know how to integrate external bindings using eclipse?
2) What other options other than external xml bindings are available?
I think you best option is to use MOXy XML bindings:
http://www.eclipse.org/eclipselink/documentation/2.6/moxy/runtime003.htm
This allows you to define XML<->Java mappings in form of XML files instead of annotations:
<?xml version="1.0" encoding="US-ASCII"?>
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="example">
<java-types>
<java-type name="Customer">
<xml-root-element name="customer-info" />
<java-attributes>
<xml-attribute java-attribute="custId" name="customer-id" />
<xml-element java-attribute="picture" name="picture-hex">
<xml-schema-type name="hexBinary" />
<xml-java-type-adapter
value="example.adapters.MyHexConverter" />
</xml-element>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
You can use this file via JAXBContextProperties.OXM_METADATA_SOURCE property:
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, iStream);
JAXBContext ctx = JAXBContext.newInstance(new Class[] { Customer.class }, properties);
So if you want several different mappings for the same class, just write several XML bindings and create your JAXBContext with corresponding files. I think this is the best options right now, with MOXy
With pure JAXB RI you can write an own annotations reader. I did this once with Annox:
http://confluence.highsource.org/display/ANX/JAXB+User+Guide
Another option was JBoss JAXBIntroductions, also based on a custom annotations reader:
https://developer.jboss.org/wiki/JAXBIntroductions
But I'm not sure this is live anymore.
Since you want multiple mappings, you'll have to write them (all but one) manually. You can generate one set of mappings as annotations, but further mappings will have to be written manually. Or, let's say, I'm not aware of a plugin or tool which would generate, for instance, MOXy XML bindings. Wouldn't be a big problem to write one though.
You may also take a completely different approach. Instead of mapping one central model with different mappings/format, you can have map a separate package of DTOs onto these formats. And then convert between your DTOs and the central model. Something like
XML(1) <-> DTO(1)|<-\
XML(2) <-> DTO(2)|<--*->Model
XML(3) <-> DTO(3)|<-/
Thus you'll have clean DTOs per exchange format (which you can generate out of schemas) and a single central business model (to rule them all). You'll have to convert between DTOs and the Model, this can be handled with a tool like Dozer.
If this is a better approach or not depends on how complex your formats are and how different they are fron one another.
Concerning your questions:
1) There's nothing special about Eclipse, just add MOXy as dependency and follow the docs.
2) I've described a few options above.
See "Passing Customization Files to the JAXB Binding Compiler" here:
https://docs.oracle.com/javase/tutorial/jaxb/intro/custom.html
You could write a script to integrate into Eclipse. Or you could use a Maven or Ant task.
Your only options are annotations or XML bindings.
Background
We have a list of tables in a database, we want to read them through select statements, then turn the result into csv files
Problem
I could use mybatis to load data from tableA then map it to a resultMap A, then using openCSV to save it as a csv file.
but I am seeking a generic way, which I only need to specify
<sql> select * from tableA </sql>
<csvFile> A.csv </csvFile>
<mapping> Table.1stName = CSV.firstName </Mapping>
<mapping> Table.2ndName = CSV.secondName </Mapping>
........
in my config.xml, and my program should be able to run the sql select
then map the resultset to a generic resutMap in mybatis? or turn
the results into xml or csv or any string format?
then I can composing the csv file using the mapping in my config
the key question is how to let the mybatis return a more generic format
of the resultset, rather than map it to a specific object.
#FlorianSchaetz indeed for low level parsing Spring JDBC comes in handy. Mybatis is a ORM, I didn't need to map the object. no need to using Mybatis. Finally the implementation is simple, Paring the XML using JAXB, then excute the sql using Spring JDBC, which returns a resultset, then according to the mapping names. extract data from the dataset, them amp to the right csv file field.
I am using hibernate reverse engineering and trying to get my Timestamps to map to a JodaTime type.
I have setup my hibernate.reveng.xml file properly
<sql-type jdbc-type="TIMESTAMP" hibernate-type="org.joda.time.contrib.hibernate.PersistentDateTime" not-null="true"></sql-type>
The issue is that when i run the rev-eng process my Java classes also get the members created as PersistentDateTime objects, but I don't want that because they are not usable. I need the java objects to be org.joda.time.DateTime
So I tried creating a custom engineering strategy
public class C3CustomRevEngStrategy extends DelegatingReverseEngineeringStrategy {
public C3CustomRevEngStrategy(ReverseEngineeringStrategy res) {
super(res);
}
public String columnToHibernateTypeName(TableIdentifier table, String columnName, int sqlType, int length, int precision, int scale, boolean nullable, boolean generatedIdentifier) {
if(sqlType==Types.TIMESTAMP) {
return "org.joda.time.DateTime";
} else {
return super.columnToHibernateTypeName(table, columnName, sqlType, length, precision, scale, nullable, generatedIdentifier);
}
}
}
My thought was that the hibernate mapping files would get the hibernate.reveng.xml file settings and the java objects would get the settings from the custom strategy file...but that was not the case. Both the mapping file and Object are of type "org.joda.time.DateTime" which is not what I want.
How can I achieve my goal? Also, I am NOT using annotations.
Hibernate 3.6
JodaTime 2.3
JodaTime-Hibernate 1.3
Thanks
EDIT: To clarify exactly what the issue is
After reverse engineering this is what I get in my mapping file and POJO class
<property name="timestamp" type="org.joda.time.contrib.hibernate.PersistentDateTime">
private PersistentDateTime timestamp;
As a POJO property, PersistentDateTime is useless to me as I cannot do anything with it such as time manipulations or anything. So this is what I want after my reverse engineering
<property name="timestamp" type="org.joda.time.contrib.hibernate.PersistentDateTime">
private org.joda.time.DateTime timestamp;
Using the Jidira library as suggested below gives me the same result, a POJO that I cannot use.
The JodaTime-Hibernate library is deprecated, and is probably the source of your problem. Don't dispair however as there is a (better) alternative.
You will need to use the JadiraTypes library to create the correct JodaTime objects from Hibernate. Add the library which can be found here to your project classpath and then change your type to org.jadira.usertype.dateandtime.joda.PersistantDateTime. All of the JodaTime objects have a corresponding mapping in that package, so if you decide to change to another object then just update your type.
This should ensure that your objects get created correctly.
I should add a caveat to my answer, which is that I have never used the JadiraTypes library with Hibernate 3. If it only supports Hibernate 4 (I don't see why it would, but...) let me know and I'll delete my answer.
The Hibernate Tools don't seem to separate Hibernate Types from the Java types. If you would be using annotations, this would be more clear as in that case you'd need an #Type annotation, which Hibernate will not generate at all. So using the exposed APIs won't help here.
Fortunately, Hibernate lets you plug into the actual code (or XML) generation after it does its processing. You can do that by replacing the Freemarker templates it uses to generate both XML and Java code. You'll need to use Ant for reverse engineering, however.
To start using Ant for this purpose (if you're not doing so already), you can either pull Hibernate Tools in as a build-time dependency using your dependency manager or download a JAR. Put the jar in Ant's classpath, but also extract the template files from it: since you're using XML configuration, you'll be interested in the /hbm directory. Then add the task using <taskdef> and, assuming that you extracted the templates to TPL_PATH/hbm/*.ftl, call it using <hibernatetool templatepath="TPL_PATH" ...>. (For more info, see below for a link to the docs). Using Ant also helps with automation, for example on CI servers where you won't have Eclipse.
You'll want to keep hibernate-type="org.joda.time.DateTime" in your hibernate.reveng.xml so that the Java files get generated correctly, but replace it with org.joda.time.contrib.hibernate.PersistentDateTime in the generated XML. To do that, edit TPL_PATH/hbm/property.hbm.ftl, replace ${property.value.typeName} with ${javaType}, and assign javaType to the right value before it's used:
<#assign javaType=property.value.typeName>
<#if javaType.equals("DateTime")>
<#assign javaType="org.jadira.usertype.dateandtime.joda.PersistentDateTime">
</#if>
<property
name="${property.name}"
type="${javaType}"
...
You might want to remove newlines to keep the generated XML clean.
This is all described in the Hibernate Tools documentation at http://docs.jboss.org/tools/archive/3.2.1.GA/en/hibernatetools/html/codegen.html#d0e6349 - except that the documentation doesn't tell you exactly which templates you need to modify, you need to figure that out by reading the templates.
i have one question. What is the best way to serialize in java 1 object to few xml with different schema? For example we have this java bean:
class User {
String name;
String gender;
String age;
}
And i want to serialize it to first
<user>
<name>bobby</name>
<gender>male</gender>
<age>40</age>
</user>
second
<info>
<employer>
<data>
<name>bobby</name>
</data>
<meta>
<gender>male</gender>
<age>40</age>
</meta>
</employer>
</info>
and maybe another one xml. What you think?
You could refer to this answer. The JAXB lib generate the serialization xml file based on a .xsd file. And of course you can customize the .xsd file for your own purpose.
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
Metadata Representation
Generally object-to-XML providers offer different ways of specifying metadata. Annotations is one way of specifying metadata and in all instances of seen annotations correspond to only one representation. So you need to look for a provider that offers an alternate approach such as an XML mapping document or programmatic metadata.
Path Based Mapping
Generally object-to-XML providers offer mapping through a 1-to-1 relationship between objects/properties and levels of nesting. To map to your second representation you need a provider that is able to do path based mapping.
MOXy offers both items that you are looking for. Below is a link to an example where a single object model is mapped to both the Google and Yahoo weather APIs:
http://blog.bdoughan.com/2011/09/mapping-objects-to-multiple-xml-schemas.html
I'm using Java and XStream to parse a google geocode request over http. My idea is to have an Address class with all the geocode attr's (ie. lat/long, city, provice/state etc) but I'm having problems parsing the xml with xstream.
The google response is similar to this:
<?xml version="1.0" encoding="UTF-8" ?>
<kml xmlns="http://earth.google.com/kml/2.0"><Response>
<name>98 St. Patrick St, Toronto</name>
<Status>
<code>200</code>
<request>geocode</request>
</Status>
<Placemark id="p1">
<address>98 St Patrick St, Toronto, ON, Canada</address>
<AddressDetails Accuracy="8" xmlns="urn:oasis:names:tc:ciq:xsdschema:xAL:2.0"> <Country><CountryNameCode>CA</CountryNameCode><CountryName>Canada</CountryName><AdministrativeArea><AdministrativeAreaName>ON</AdministrativeAreaName><Locality><LocalityName>Toronto</LocalityName><Thoroughfare><ThoroughfareName>98 St Patrick St</ThoroughfareName></Thoroughfare><PostalCode><PostalCodeNumber>M5T</PostalCodeNumber></PostalCode></Locality></AdministrativeArea></Country></AddressDetails>
<ExtendedData>
<LatLonBox north="43.6560378" south="43.6497426" east="-79.3864912" west="-79.3927864" />
</ExtendedData>
<Point><coordinates>-79.3896388,43.6528902,0</coordinates></Point>
</Placemark>
</Response></kml>
That doesn't show up very well, but the meat of the code is in the AddressDetails tag.
Anyway, I'm new to Java and XStream so the API terminology is a bit confusing for me. I just need to be able to write some mapper that maps all these tags (ie. CountryName) to an attribute within my Address object, (ie. address.country = blah) The address object will be pretty simple, mainly just strings for country name etc and floats for lat/long.
The docs and example just show straight mapping where each xml tag maps directly to the attribute of the same name of the object. In my case however, the tags are named different than the object attr's. A quick point in the right direction is all I'm looking for really.
I've used XStream in several projects. Unfortunately, your problem isn't really what XStream is designed to solve. You might be able to use its converter mechanism to achieve your immediate goal, but you'll run into limitations. In a nutshell, XStream isn't designed to do conversion of Tree Structure A into Tree Structure B -- it's purpose is to convert from a Java domain model into some reasonable XML. XStream is a great tool when you don't care much about the details of the XML produced. If you care more about the XML than the Java objects, look at XMLBeans -- the Java is ugly, but it's incredibly schema-compliant.
For your project, I'd run the Google XML schema through XML beans, generate some Java that will give you a more literate way of hand-coding a converter. You could use a raw DOM tree, but you'd have code like myAddress.setStreet(root.getFirstChild().getAttribute("addr1"))). With XML beans, you say things like myAddress.setStreet(googleResult.getAddress().getStreetName();
I'd ignore JAXB as it's attempt to separate interface from implementation adds needless complexity. Castor might be a good tool to consider as well, but I haven't used it in years.
In a nutshell, there aren't a lot of good Object-to-Object or XML-to-Object converters that handle structure conversion well. Of those I've seen that attempt declarative solutions, all of them seemed much more complicated (and no more maintainable) than using XStream/XmlBeans along with hand-coded structure conversions.
Would it be possible to define a separate class specifically for dealing with XStream's mapping? You could then simply populate your AddressDetails object by querying values out of this other object.
I've ended up just using xpath and populating my own address object manually. Seems to work fine.
Have you tried with json format? It should be the same but you'll need to set a com.thoughtworks.xstream.io.json.JettisonMappedXmlDriver as the driver for XStream
You could use EclipseLink JAXB (MOXy) to do this:
package com.example;
import javax.xml.bind.annotation.XmlRootElement;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement(name="kml")
public class Address {
private String country;
#XmlPath("Response/Placemark/ns:AddressDetails/ns:Country/ns:CountryName/text()")
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
}
and
#javax.xml.bind.annotation.XmlSchema(
namespace = "http://earth.google.com/kml/2.0",
xmlns = {
#javax.xml.bind.annotation.XmlNs(
prefix = "ns", namespaceURI ="urn:oasis:names:tc:ciq:xsdschema:xAL:2.0")
},
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.example;
A full example is available here:
http://bdoughan.blogspot.com/2010/09/xpath-based-mapping-geocode-example.html