Jibx always gives "Error during validation: null" - jibx

I'm really stumped on this incredibly simple mapping. It looks just like one of the examples even. If I comment out the internal structure, it'll run the binding compiler successfully. If I put the internal structure back in, it fails. Note that the internal structure is just defining the XML. This is basically example5 of the JIBX tutorial examples.
<binding>
<mapping name="RequestTransaction" class="TransactionRequest">
<value name="version" set-method="setVersion" get-method="getVersion" style="attribute" />
<structure name="transHeader">
<value name="requestCount" set-method="setRequestCount" get-method="getRequestCount"/>
</structure>
</mapping>
<binding>
Then I get the following error on the jibx compile:
Error: Error during validation: null; on mapping element at (line 2, col 97, in jibx-binding.xml)
I'm absolutely stumped and out of ideas. Google shows nothing useful.

The <structure> is arguably the most important concept in JiBX binding because it allows you to map arbitrary XML to your Java classes without forcing you to create bloated and ugly layers of nested Java objects and classes to match the XML design.
In this case your binding declares that you have an XML element named <transHeader> that will not be present in your Java class.
With some slight fixes to your XML format, your binding works perfectly. I assume the fact that your binding has two <binding> open tags rather than and open and close <binding></binding> is a typo, because you said you got it to work without the structure. Also add <?xml version="1.0"?> at the top of your binding file. Those two XML mods allow the JiBX 1.2 binding compiler to work with the following Java class:
(Note: you didn't provide the Java class this binding is for so I had to reconstruct it from the info you put in the binding file. The obvious side effect of this is that I reconstructed a class that will work with this binding. But the simple fact is that a JiBX binding by design contains all the info you need to know about the class and the XML.)
public class TransactionRequest {
private String version;
private int requestCount;
public void setVersion(String ver) {
version = ver;
}
public String getVersion() {
return version;
}
public void setRequestCount(int count) {
requestCount = count;
}
public int getRequestCount() {
return requestCount;
}
}
compile the class then run the binding compiler with:
>java -jar jibx-bind.jar jibx-binding.xml
To test it I used the following sample.xml:
(Note: you also didn't provide the XML you are trying to map so again I created a sample based on what you did provide)
<?xml version="1.0"?>
<RequestTransaction version="0.1">
<transHeader>
<requestCount>3</requestCount>
</transHeader>
</RequestTransaction>
Running the test uses the following code:
public static void main(String[] argz) {
String fileName = "./sample.xml";
IBindingFactory bfact = null;
IUnmarshallingContext uctx = null;
TransactionRequest sample = null;
try {
bfact = BindingDirectory.getFactory(TransactionRequest.class);
uctx = bfact.createUnmarshallingContext();
InputStream in = new FileInputStream(fileName);
sample = (TransactionRequest)uctx.unmarshalDocument(in, null);
System.out.println(sample.getRequestCount());
System.out.println(sample.getVersion());
}
catch (Exception e) {
e.printStackTrace();
}
}
And it runs successfully.

It's been a while now, but I found it was related to inheritance. I needed to give mappings for everything in the inheritance tree, including interfaces as I recall.
I ended up creating a wrapper object, which I've found seems to be the easiest way to use JIBX in general. Trying to map a true domain class causes tendrils into every class that class touches and I have to unjar everything so JIBX can find the classes, including 3rd party libs.

Related

SpringBatch - how to set up via java config the JsonLineMapper for reading a simple json file

How to change from "setLineTokenizer(new DelimitedLineTokenizer()...)" to "JsonLineMapper" in the first code below? Basicaly, it is working with csv but I want to change it to read a simple json file. I found some threads here asking about complex json but this is not my case. Firstly I thought that I should use a very diferent approach from csv way, but after I read SBiAch05sample.pdf (see the link and snippet at the bottom), I understood that FlatFileItemReader can be used to read json format.
In almost similiar question, I can guess that I am not in the wrong direction. Please, I am trying to find the simplest but elegant and recommended way for fixing this snippet code. So, the wrapper below, unless I am really obligated to work this way, seems to go further. Additionally, the wrapper seems to me more Java 6 style than my tentative which takes advantage of anonimous method from Java 7 (as far as I can judge from studies). Please, any advise is higly appreciated.
//My Code
#Bean
#StepScope
public FlatFileItemReader<Message> reader() {
log.info("ItemReader >>");
FlatFileItemReader<Message> reader = new FlatFileItemReader<Message>();
reader.setResource(new ClassPathResource("test_json.js"));
reader.setLineMapper(new DefaultLineMapper<Message>() {
{
setLineTokenizer(new DelimitedLineTokenizer() {
{
setNames(new String[] { "field1", "field2"...
//Sample using a wrapper
http://www.manning.com/templier/SBiAch05sample.pdf
import org.springframework.batch.item.file.LineMapper;
import org.springframework.batch.item.file.mapping.JsonLineMapper;
import com.manning.sbia.ch05.Product;
public class WrappedJsonLineMapper implements LineMapper<Product> {
private JsonLineMapper delegate;
public Product mapLine(String line, int lineNumber) throws Exception {
Map<String,Object> productAsMap
= delegate.mapLine(line, lineNumber);
Product product = new Product();
product.setId((String)productAsMap.get("id"));
product.setName((String)productAsMap.get("name"));
product.setDescription((String)productAsMap.get("description"));
product.setPrice(new Float((Double)productAsMap.get("price")));
return product;
}
public void setDelegate(JsonLineMapper delegate) {
this.delegate = delegate;
}
}
Really you have two options for parsing JSON within a Spring Batch job:
Don't create a LineMapper, create a LineTokenizer. Spring Batch's DefaultLineMapper breaks up the parsing of a record into two phases, parsing the record and mapping the result to an object. The fact that the incoming data is JSON vs a CSV only impacts the parsing piece (which is handled by the LineTokenizer). That being said, you'd have to write your own LineTokenizer to parse the JSON into a FieldSet.
Use the provided JsonLineMapper. Spring Batch provides a LineMapper implementation that uses Jackson to deserialize JSON objects into java objects.
In either case, you can't map a LineMapper to a LineTokenizer as they accomplish two different things.

Sitecore Configuration Factory - Call method with more than one argument

I have read John West's article on the Site Configuration Factory (http://www.sitecore.net/unitedkingdom/Community/Technical-Blogs/John-West-Sitecore-Blog/Posts/2011/02/The-Sitecore-ASPNET-CMS-Configuration-Factory.aspx)
I'm trying implement it in a custom link provider.
I want the Configuration Factory to call the following method in the link provider:
public void AddSitePath(String site, String path)
{
// do stuff
}
Here's the config (although I've tried several similar variations).
<add name="sitecore" type="MyProject.Providers.CustomLinkProvider, MyProject" addAspxExtension="false" alwaysIncludeServerUrl="false" encodeNames="true" languageEmbedding="never" languageLocation="filePath" shortenUrls="true" useDisplayName="false">
<sitePaths hint="list:AddSitePath">
<sitePath>
<site>SiteOneName</site>
<path>/product-range/</path>
</sitePath>
<sitePath >
<site>SiteTwoName</site>
<path>/items-for-sale/</path>
</sitePath>
</sitePaths>
</add >
I'm getting the following error message:
Could not find add method: AddSitePath (type: MyProject.Providers.CustomLinkProvider)
I suspected that the problem was that I was trying to pass 2 parameters into the method, and sure enough, when I tested it with a single parameter version it worked.
What do I need to change in either the config or the class code to achieve what I need?
So it looks like you can't supply 2 arguments. Instead, you pass in a single XmlNode object, which contains everything you you need. You have to extract the information from the XmlNode within the method.
Something along the lines of:
public void AddSitePath(XmlNode arg)
{
// pick apart the XmlNode and do stuff
}
<sitePaths hint="raw:AddSitePath">
<sitePath site="SiteNameOne" path="/product-range/">
<sitePath site="SiteNameTwo" path="/items-for-sale/">
</sitePaths>
Note that you have to use the 'raw' prefix instead of 'list'

Custom Neo4j GraphViz Writer

I have an application which produces a GraphViz dot file for a subgraph of my Neo4j database. It works like a charm, but there is somewhat of an issue.
Right now, the title of each node is the node id. Then the properties are listed, with their respective types. This is more information than I need and I would like to change the way the GraphViz writer is configured.
I noticed several classes/interfaces such as GraphStyle, StyleParameter, StyleConfiguration but I've tried several things and keep running into the issue that I cannot access certain classes/interfaces outside of their respective package. Maybe I'm doing it wrong, maybe it's designed so users cannot reconfigure the GraphViz writer, I don't know but I'd like to know.
How do I reconfigure the GraphViz writer so the dot file contains only that information which I want it to contain, namely a property of my choosing as the title, and nothing else as far as the nodes are concerned. Also, this is not always the same property, so for some nodes I'd like property A to be the title, and for nodes that don't have property A, I'd like property B to be the title.
Any help would be greatly appreciated.
You could try using the styles provided by this class: https://github.com/neo4j/neo4j/blob/master/community/graphviz/src/main/java/org/neo4j/visualization/graphviz/AsciiDocSimpleStyle.java
It might be useful to look into this class as well: https://github.com/neo4j/neo4j/blob/master/community/graphviz/src/main/java/org/neo4j/visualization/asciidoc/AsciidocHelper.java
I managed to get it to work. First of all, you need to create two new classes:
class NodeStyleImpl implements NodeStyle
class RelationshipStyleImpl implements RelationshipStyle
Here you can define how nodes and relations should be written in the dot notation. An example implementation looks like this :
public class NodeStyleImpl implements NodeStyle {
public void emitNodeStart(Appendable apndbl, Node node) throws IOException {
apndbl.append(" N" + node.getId() + " [\n label = \"");
}
public void emitEnd(Appendable apndbl) throws IOException {
apndbl.append("\"\n]\n");
}
public void emitProperty(Appendable apndbl, String propkey, Object propvalue) throws IOException {
if(propkey.equals("propkeyone") || propkey.equals("propkeytwo"){
apndbl.append(propvalue.toString());
}
}
}
In an analog fashion, you can write the RelationshipStyleImpl. If you're looking for more advanced configuration, you can also write a StyleConfiguration implementation. You can look at the default implementations in the Neo4j code for an example.
Then there's the issue with the GraphStyle class. The GraphStyle class has a constructor which is protected, thus only accessible from within the package. I made a pull request to change it to public but for the moment, here's a little "hack" which provides a workaround.
package org.neo4j.visualization.graphviz
public class GraphStyleImpl extends GraphStyle {
private GraphStyleImpl (NodeStyleImpl nstyle, RelationshipStyleImpl rstyle) {
super(nstyle, rstyle);
}
}
Note the package declaration. Because the GraphStyle constructor is protected, the super(nstyle, rstyle) method is only accessible from within the same package. By extending the class with a new public constructor, you can now do the following:
GraphStyle graphstyle = new GraphStyleImpl(new NodeStyleImpl(), new RelationshipStyleImpl());
GraphvizWriter writer = new GraphvizWriter(graphstyle);
If my pull request gets accepted, the use of the GraphStyleImpl class will no longer be necessary.

jaxbcontext.newinstance() with eclipselink MOXy hangs

disclaimer: I'm incredibly amateur at all of this
I'm trying to get the project I'm working on to output JSON in addition the XML.
Originally the prior method to do so involved a method that took in an argument of Element and recursively inserted things into an object of type net.sf JSONObject to create the JSON output, and used the normal JAXBContext's Marshaller to marshal into XML.
What I wanted was to use MOXy as my JAXB provider, and then marshal out both XML and JSON from the bindings.
Originally, when the XML was marshalled, I had:
jc = JAXBContext.newInstance("packageA:packageB:packageC...etc.");
public static String marshal(JAXBContext context, JAXBElement<?> je) throws JAXBException {
StringWriter sout = new StringWriter();
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.FALSE);
m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
m.marshal(je, sout);
return sout.toString();
}
and then
JAXBElement<myObject> jaxb =
new JAXBElement<myObject>(myObject_QNAME, myObject.class, null, value);
return XmlResponseMessage(marshal(jc, jaxb));
}
(this is probably important, so I should mention that the application I'm working on uses the spring framework.)
Also, I've read every single one of Blaise's blog posts regarding EclipseLink. Some multiple times. I just have a very shallow understanding of it and would appreciate if instead of linking me to one of his pages you explained whatever solution on it is and why it works
That being said, I tried just including the jaxb.properties file in one of the packages to try to get MOXy as opposed to JAXBElement to get my bindings.
however, JAXBContext.newInstance("my list of : delimited packages") just makes the program hang. not even an error, just hangs it. stepping through just shows the call to the EclipseLink newInstance method hanging.
I've looked for many hours for solutions online. I have much too many classes to just include in a Class[], and so can't set the property by using an array of classes. which is also the reason I couldn't use the native moxy API instead of using the property file. I think i have EclipseLink set up correctly: I've set eclipselink_home in my environment variables, and added the eclipselink.jar to my buildpath.
UPDATE #2
A fix for this issue has been checked into the EclipseLink 2.4.2 and 2.5.0 streams and a nightly build containing the fix can be downloaded from the following link starting March 12, 2013:
http://www.eclipse.org/eclipselink/downloads/nightly.php
UPDATE #1
After a couple of email exchanges I think the problem you are encountering is due to the following bug. You can use the link to track our progress on this issue.
http://bugs.eclipse.org/402801
I'll demonstrate how it manifests itself below:
ObjectFactory
For the problem to occur you need to have an #XmlElementDecl annotation where thename is the same as the substitutionHeadName.
#XmlRegistry
public class ObjectFactory {
#XmlElementDecl(name="foo", substitutionHeadName="foo")
public JAXBElement<Foo> createBar(Foo foo) {
return new JAXBElement<Foo>(new QName("foo"), Foo.class, foo);
}
}
Domain Object (Foo)
Then on one of your domain objects you need to have an #XmlElementRef annotation referencing the element we defined in the #XmlElementDecl.
public class Foo {
#XmlElementRef(name="foo")
public Foo foo;
}
Demo
You will see the problem when you create the JAXBContext.
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Foo.class, ObjectFactory.class);
System.out.println(jc.getClass());
}
}
Trace
MOXy gets in an infinite loop adding the reference element.
...
at org.eclipse.persistence.jaxb.compiler.AnnotationsProcessor.addReferencedElement(AnnotationsProcessor.java:3740)
at org.eclipse.persistence.jaxb.compiler.AnnotationsProcessor.addReferencedElement(AnnotationsProcessor.java:3740)
at org.eclipse.persistence.jaxb.compiler.AnnotationsProcessor.addReferencedElement(AnnotationsProcessor.java:3740)
at org.eclipse.persistence.jaxb.compiler.AnnotationsProcessor.addReferencedElement(AnnotationsProcessor.java:3740)
at org.eclipse.persistence.jaxb.compiler.AnnotationsProcessor.addReferencedElement(AnnotationsProcessor.java:3740)
at org.eclipse.persistence.jaxb.compiler.AnnotationsProcessor.addReferencedElement(AnnotationsProcessor.java:3740)
at org.eclipse.persistence.jaxb.compiler.AnnotationsProcessor.addReferencedElement(AnnotationsProcessor.java:3740)
at org.eclipse.persistence.jaxb.compiler.AnnotationsProcessor.addReferencedElement(AnnotationsProcessor.java:3740)
at org.eclipse.persistence.jaxb.compiler.AnnotationsProcessor.addReferencedElement(AnnotationsProcessor.java:3740)
...
ORIGINAL ANSWER
You could try using the following to create your JAXBContext. It bypasses the standard JAXB impl lookup code by using native MOXy code.
JAXBContext jc = org.eclipse.persistence.jaxb.JAXBContextFactory.createContext("packageA:packageB:packageC...etc.");
If that works we'll know the problem is related to the impl look up code and we can go from there.

Return plain objects in entity framework for serialization

I have been trying out both Linq to Sql and EF in my ASP.NET MVC application. After switching to EF I realized my XML/JSON serialization output has extra cruft.
XML:
<Test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<EntityKey>
<EntitySetName>Persons</EntitySetName>
<EntityContainerName>PersonEntities</EntityContainerName>
<EntityKeyValues>
<EntityKeyMember>
<Key>Id</Key>
<Value xsi:type="xsd:int">1</Value>
</EntityKeyMember>
</EntityKeyValues>
</EntityKey>
<Id>1</Id>
<Name>John</Name>
</Test>
JSON:
{"Id":1,"Name":"John","EntityState":2,"EntityKey"{"EntitySetName":"Persons","EntityContainerName":"PersonEntities","EntityKeyValues":[{"Key":"Id","Value":1}],"IsTemporary":false}}
Instead I would just like my output to be:
{"Id":1, "Name":"John"}
My EF query to retrieve the object is:
Tests.First(t => t.Id == testId);
You can shape the JSON result in your controller like this:
public JsonResult Person(int id)
{
var person = PersonRepository.FindByID(id);
var result = new { Id = person.Id, Name = person.Name };
return Json(result);
}
This will limit the DTO which is serialized to contain only the values you want.
Edit:
As a paritial answer to your comment question; you can create a simpler PersonViewModel class (DTO) that you can map the properties to. As John Saunders mentioned in his answer Automapper is a nice way to simplify the copying of the property values out of the EF Person instance:
The modified Action method may look like this:
public JsonResult Person(int id)
{
var person = PersonRepository.FindByID(id);
var dto = Mapper.Map<Person, PersonViewModel>(person);
return Json(dto);
}
The only other option I can think of is to use reflection to modify the DataMemberAttributes on the Person entity to suppress the EntityKey property.
Another approach to work around this is to use the JavascriptSerializer's ScriptIgnore attribute and create a partial class for the object in question, new'ing up the EntityKey, EntityState properties and adding a ScriptIgnore attribute to them:
public partial class Person
{
[ScriptIgnore]
public new System.Data.EntityKey EntityKey { get; set; }
[ScriptIgnore]
public new System.Data.EntityState EntityState { get; set; }
}
When the Person class is serialized via JavascriptSerializer, it will ignore those properties. However, this would not be practical because EF uses the state info to keep track of objects and this would wreak havoc.
If there were a way to dynamically add properties, it would eliminate the need to override those properties just to add a [ScriptIgnore] attribute. But, since there is no way to dynamically add attributes, this solution may not be that useful.
So far, the best technique I've found involves code generation. I did this on one project that was using the Service Factory, but you could do the same "by hand" using T4 Text templates directly.
Also, keep an eye on AutoMapper. It's still new enough that I consider it to be emerging technology, but I'm hoping it will emerge soon!