XML unmarshalling with Castor and Grails - java

I have a grails project that contains a few domain objects. I am using a java project in this code which can parse a document for me. The controller that calls that Java project is using JAXB to generate XML from the object returned by the Java project.
I want to use this XML document (which is generated after some text parsing, using JAXB) to populate my Domain classes in my grails project. How does this work in grails? Can I use something like Castor, and create a mapping using the names of my groovy classes? The idea is I want to generate new entries in the database and save it for the user based on whatever text was parsed out of the document they uploaded.
How does this even work in grails anyway? Can I create a new Domain object from another object's controller with something like
Project p = new Project();
and then do a p.save()?

Download the Castor Core and Castor XML jars from here and put them in the lib directory (there's probably a better way to manage this dependency using Grails' dependency management, but this one's a quick and dirty).
With Castor introspection mode you don't need to worry about creating mapping files if your XML matches up nicely with your domains. Here's an example:
grails-app/domain/MyDomain.groovy
class MyDomain {
String foo
String bar
}
grails-app/controllers/MyController.groovy
import org.exolab.castor.xml.Unmarshaller
import java.io.ByteArrayInputStream
class MyController {
def myAction = {
def xml = '''
<myDomain>
<foo>My Foo String</foo>
<bar>My Bar String</bar>
</myDomain>
'''
def reader = new ByteArrayInputStream(xml.bytes).newReader()
def domain = (MyDomain)Unmarshaller.unmarshal(MyDomain.class, reader)
domain.save()
def count = MyDomain.countByFoo('My Foo String')
render "Found $count results"
}
}
Navigate to localhost:8080/appname/my/myAction and it should display "Found N results", N > 0.

Related

How can I parse yaml comments using java?

I want to use a yml configuration file in my project. I am using jackson-dataformat-yaml for parsing yml files. But I need to parse yml comments as well. I used the similar approach in python using ruamel yaml. How can I do the same in java?
Upd.
What for? Well, I wanted to make it possible to override my configuration options by using command line arguments. So, to generate description message for each option, I wanted to use my comments. Like this:
In my config.yml
# Define a source directory
src: '/foo/bar'
# Define a destination directory
dst: '/foo/baz'
So when you run your program with the --help flag, you'll see the following output:
Your program can be ran with the following options:
--src Define a source directory
--dst Define a destination directory
The main benefit in such a model is that you don't ever need to repeat the same statement twice, because they can be retrieved from the configuration file.
Basically, you have three layers of data:
Your configuration schema. This defines the values that are to be defined in the configuration file.
The configuration file itself, which describes the usual configuration on the current machine.
One-time switches, which override the usual configuration.
The descriptions of what each value does belong to the schema, not to the configuration file itself. Think about it: If someone edits the configuration file on their machine and changes the comments, your help output would suddenly show different descriptions.
My suggestion would be to add the descriptions to the schema. The schema is the Java class you load your YAML into. I am not sure why you are using Jackson, since it uses SnakeYaml as parser and SnakeYaml is perfectly able to deserialize into Java classes, but has more configuration options since it does not generalize over JSON and YAML like Jackson does.
Here's a general idea how to do it with SnakeYaml (beware, untested):
// ConfigParam.java
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface ConfigParam { String description(); }
// Configuration.java
public class Configuration {
#ConfigParam("Define a source directory")
String src;
#ConfigParam("Define a destination directory")
String dst;
}
// loading code
Yaml yaml = new Yaml(new Constructor(Configuration.class));
Configuration config = yaml.loadAs(input, Configuration.class);
// help generation code
System.out.println("Your program can be ran with the following options:")
for (Field field: Configuration.class.getFields()) {
ConfigParam ann = field.getAnnotation(ConfigParam.class);
if (ann != null) {
System.out.println(String.format("--%s %s", field.getName(), ann.description());
}
}
For mapping actual parameters to the configuration, you can also loop over class fields and map the parameters to the field names after having loaded the configuration (to replace the standard values with the given ones).

Java: xml to singleton (using maven & jaxb)

I want to do such thing completely automatically by maven.
I have a .xml file with some data. There is some references by ids from one object in this xml to another, and so on. I don't have .xsd of this .xml.
I need exactly two things:
1) Compile this xml to Java classes.
2) Creating one Singleton class named by this .xml name and containing all .xml data relative the inner .xml structure.
For example, my .xml looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<MyBigSinletonWithAllData>
<Cars>
<Car id="1" speed = "5"/>
<Car id="2" speed = "3"/>
</Cars>
</MyBigSinletonWithAllData>
And I want to get somehting like this, as automatic output:
class MyBigSinletonWithAllData {
List<Cars> cars;
}
class Car {
double speed;
}
class MyBigSinletonWithAllDataSingleton {
MyBigSinletonWithAllData INSTANCE = new MyBigSinletonWithAllData();
/* And here we read an INSTANCE from our .xml file */
}
So, my question is how to do this fully automatically by Maven?
I don't want to code manually the "MyBigSinletonWithAllDataSingleton", I just want to get it already generated for me, so I need only to write code line like this:
MyBigSinletonWithAllDataSingleton.INSTANCE
to get full access to all data that written in relative .xml file.
For now I use "maven-jaxb2-plugin" to generate Java classes from .xsd; But I also need a tool that do .xsd from .xml, and tool that create automatically read/write operations to singleton.
In Java SOAP based webservices there are different implementation like apache axis and apche cxf. In that implementations we have tools which we will run or simply we will pass the XML file to that tool so corresponding binding classes will be generated.
Please look into their code so that it will helps you.
or may be some different tools also will be there(google it).
And yes you can convert xml to xsd file.
Go through the link
Conver XML to XSD

XML unmarshalling

I want to unmarshall the below XML file
<uc-export clientvers="9.00">
<JOBS_WINDOWS AttrType="WINDOWS" client="0001" name="BEP.WIN.SRZ2AY" system="UC4_EXP">
<ATTR_JOBS state="1">
<AutoDeactNo>6</AutoDeactNo>
<ActAtRun>2</ActAtRun>
</ATTR_JOBS>
</JOBS_WINDOWS>
</uc-export>
want to get the value of in my java program.
I have found a complex solution as of now if there any simple way to proceed rather than creating java class inside another java class.
You can try using JAXB Java Architecture for XML Binding. See here for an example.
Another option to consider is Apache XMLBeans. In XMLBeans, you would create an XSD file which the above XML you gave matches. XMLBeans would compile this XSD file and generate an XmlObject POJO corresponding to the XSD file. Let us call this class (interface) YourXMLDocument. Once these steps are out of the way, you can simply parse your input XML file ("input.xml") with the following line of code:
YourXMLDocument yourDoc = YourXMLDocument.Factory.parse("input.xml");
See here for more information.

load class only

I have developed eclipse plugin which for any given java project create GUI in form of package structure. I have successfully run my plugin for different java project.
Now, I thought should try my code in some open source project, therefore, I download JDOM Framework.
However, I found that the JDOM source code has this structure.
JDOM -> contrib -> src -> java -> org -> jdom2......
where as i assume that the project will have always below structure
Project Name -> Src -> PACKAGE NAME STARTS HERE.....
I load the classes using below code,
IPackageFragment[] packages = javaProject.getPackageFragments();
for (IPackageFragment mypackage : packages) {
if (mypackage.getKind() == IPackageFragmentRoot.K_SOURCE) {
for (ICompilationUnit unit : mypackage.getCompilationUnits()) {
// unit.getPath().toString() give me path, but how to extract only class name with package
// save it in to MAP with Package as key
}
}
}
Now, I want to show classes with only package name, therefore, I remove first two string (PROJECT NAME, SRC), but this cannot be always the case as for JDOM Framework.
Therefore, how can I get only package name along with class name using my method above? Or should I use different mechanism?
Looking at the directory structure alone seems to be an awfully error-prone way to go about it. Who knows how deep the directory tree goes? If instead you scan for Java source files, you should be able to construct a reader that finds the package declaration at the beginning of the file. If there isn't one, you don't need to worry about it. Do I need to say you can store package names in a HashSet to avoid duplicate package declarations?
The ICompilationUnit has a findPrimaryType method:
IType primaryType = unit.findPrimaryType();
and IType has getFullyQualifiedName():
String name = primaryType.getFullyQualifiedName();

How can I get all #Entity classes from a Persistence Unit?

Problem
I'm writing a standalone utility program which, given a jar containing a JPA-2 annotated persistence unit, needs to programmatically get a list of all my #Entity classes in a particular persistence unit.
I'd like to decide which of 2 approaches would be the way to go to get this information, and why; or if there is another better way I haven't thought of.
Solution 1
Java program puts jar on the classpath, creates persistence unit from the classes in the jar using JavaSE methodologies. Then it uses the javax.persistence classes to get the JPA Metamodel, pull back list of class tokens from that.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("MY_ PERSISTENCE_UNIT");
Metamodel mm = emf.getMetamodel();
// loop these, using getJavaType() from Type sub-interface to get
// Class tokens for managed classes.
mm.getManagedTypes();
Solution 2
Program scan the directories and files inside the specified jar for persistence.xml files, then finds one with the specified persistence unit name. Then XPath the file to get the list of <class> XML elements and read the fully qualified class names from there. From names, build class tokens.
Constraints/Concerns
I'd like to go with approach 1 if possible.
This utility will NOT run inside a container, but the jar is an EJB project designed to run inside one. How will this be a problem?
The utility will have Open-EJB available on the classpath to get implementations of all the Java EE 6 classes.
Even though the EJB project is built to run on Hibernate, the utility should not be Hibernate-specific.
Are there any stumbling blocks?
In case anyone's interested, Solution 1 worked. Here's essentially what I had to do:
public MySQLSchemaGenerator() throws ClassNotFoundException {
Properties mySQLDialectProps = new Properties();
mySQLDialectProps.setProperty("javax.persistence.transactionType", "RESOURCE_LOCAL");
mySQLDialectProps.setProperty("javax.persistence.jtaDataSource", "");
final EntityManagerFactory emf = Persistence.createEntityManagerFactory("<persistence_unit_name>", mySQLDialectProps);
final Metamodel mm = emf.getMetamodel();
for (final ManagedType<?> managedType : mm.getManagedTypes()) {
managedType.getJavaType(); // this returns the java class of the #Entity object
}
}
The key was to override my transaction type and blank out the jtaDataSource which had been defined in my persistence.xml. Turns out everything else was unnecessary.
If Your jar is well-formed (persistence.xml at the right place - in the META-INF folder), then all looks fine.
It is not necessary to run your utility inside a container, JPA is not a part of JavaEE specs.

Categories

Resources