org.springframework.oxm.jibx.JibxMarshallingFailureException: JiBX marshalling exception: Collection item of type uk.co.bigsoft.proj.event.DeleteEvent has no binding defined; nested exception is org.jibx.runtime.JiBXException: Collection item of type uk.co.bigsoft.proj.event.DeleteEvent has no binding defined at org.springframework.oxm.jibx.JibxUtils.convertJibxException(JibxUtils.java:49) at org.springframework.oxm.jibx.JibxMarshaller.convertJibxException(JibxMarshaller.java:169) at org.springframework.oxm.jibx.JibxMarshaller.marshalWriter(JibxMarshaller.java:193) at org.springframework.oxm.AbstractMarshaller.marshalStreamResult(AbstractMarshaller.java:256) at org.springframework.oxm.AbstractMarshaller.marshal(AbstractMarshaller.java:97) at uk.co.bigsoft.proj.event.TestDeleteEvent.testGet(TestDeleteEvent.java:104) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at junit.framework.TestCase.runTest(TestCase.java:168) at junit.framework.TestCase.runBare(TestCase.java:134) at junit.framework.TestResult$1.protect(TestResult.java:110) at junit.framework.TestResult.runProtected(TestResult.java:128) at junit.framework.TestResult.run(TestResult.java:113) at junit.framework.TestCase.run(TestCase.java:124) at junit.framework.TestSuite.runTest(TestSuite.java:232) at junit.framework.TestSuite.run(TestSuite.java:227) at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:81) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:45) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196) Caused by: org.jibx.runtime.JiBXException: Collection item of type uk.co.bigsoft.proj.event.DeleteEvent has no binding defined at uk.co.bigsoft.proj.event.DeleteEvent.JiBX_MungeAdapter.JiBX_jibx_isa_marshal_1_0() at uk.co.bigsoft.proj.event.DeleteEvent.JiBX_jibx_isa_marshal_1_0(EventsContainer.java) at uk.co.bigsoft.proj.event.DeleteEvent.JiBX_jibx_isaEventsContainer_access2.marshal() at uk.co.bigsoft.proj.event.DeleteEvent.marshal(EventsContainer.java) at org.jibx.runtime.impl.MarshallingContext.marshalRoot(MarshallingContext.java:1041) at org.jibx.runtime.impl.MarshallingContext.marshalDocument(MarshallingContext.java:1133) at org.springframework.oxm.jibx.JibxMarshaller.marshalWriter(JibxMarshaller.java:190) … 22 more…but there is a binding definition for my type X!
<mapping name="eventscontainer"
class="uk.co.bigsoft.proj.event.EventsContainer">
<collection
field="events"
factory="uk.co.bigsoft.proj.event.createEventsContainer">
<structure
name="isaeventcreate"
type="uk.co.bigsoft.proj.event.CreateEvent">
<value name="zone" field="zone"/>
</structure>
<structure
name="isaeventmodify"
type="uk.co.bigsoft.proj.event.ModifyEvent">
<value name="zone" field="zone"/>
</structure>
</collection>
In JibX you can serialise collections. The collection may contain different types. In my case they were a set of classes which all implemented the same interface. In JibX you need to define the elements that can appear in a collection, but the collection is by default ordered. When de-serialising the collection it can contain 3 of the first element, 0 of the second, 2 of the next and so on - but they have to be in the order laid out in the binding-mapping. What you can’t do, is have them come in any order.
If you want the collection to be able to de-serialise objects in any order, you need to flag it as not ordered. There is a performance hit for this but I think it is worth it. Alternatively, you must make sure that your collection is ordered in the same way as your XML schema definition, which is not always possible.
So from the example above add the ordered attribute to the collection elements:
<mapping name="eventscontainer"
class="uk.co.bigsoft.proj.event.EventsContainer">
<collection
field="events"
ordered="false"
factory="uk.co.bigsoft.proj.event.createEventsContainer">
:
Finding the differences between files under DOS is a pain, because DOS does not provide any tools to help manipulate files or streams of files.
When I have source trees I need to compare I use the unix power tool diff
. Sometimes (because of various editor settings) some of the files will have carriage returns and line feeds (DOS style) and some will have just carriage returns (Unix style). This can make finding differences a bit tricky because every line is different.
There is a set of commands called dos2unix
and unix2dos
which helps with stripping (or adding respectively) the line feeds, but on some servers it is not installed. Having just done this with 200 files, I thought I'd share the wealth and give it to the world.
for fn in `find . -type f -name "*.java" -print | sort`
do
echo "$fn"
sed 's/^M//' $fn > $fn.new
mv $fn $fn.old
mv $fn.new $fn
done
Note: that the ^M character is the line feed character. This is obtained by (under bash and most other shells) control+v then press return.
Give things a quick check then delete the originals with:
rm -f `find . -name "*.old"`
Another way to do the same job is to use ed
. Create a new file called line-stripper.vi
with the following lines:
%s/^M//
wq
Where `^M is the linefeed described above. Then just apply that to every file:
for fn in `ls *.hbm.xml`
do
cat line-stripper.vi | ed $fn
done
If there are too many files to delete this way then check out my post on rm: Argument list too long.- Serialiser and de-serialiser for the java.util.UUID class
- java.util.UUID generator
- Hibernate type
UUIDUserType
class below was mostly lifted from the Springframework forum site. Thanks bessette for the starting point. I have added the corrections he discovered.
This class takes care of converting a java.util.UUID into something that the database column can coup with and converting the contents of a database column into a normal java.util.UUID. More information can be found in the JavaDoc for UserType.
package uk.co.bigsoft.project.db.types ;
import java.io.Serializable ;
import java.sql.PreparedStatement ;
import java.sql.ResultSet ;
import java.sql.SQLException ;
import java.sql.Types ;
import java.util.UUID ;
import org.hibernate.HibernateException ;
import org.hibernate.usertype.UserType ;
public class UUIDUserType implements UserType
{
private static final String CAST_EXCEPTION_TEXT = " cannot be cast to a java.util.UUID." ;
/*
* (non-Javadoc)
* @see org.hibernate.usertype.UserType#assemble(java.io.Serializable,
* java.lang.Object)
*/
public Object assemble (Serializable cached, Object owner) throws HibernateException
{
if (!String.class.isAssignableFrom (cached.getClass ()))
{
return null ;
}
return UUID.fromString ((String) cached) ;
}
/*
* (non-Javadoc)
* @see org.hibernate.usertype.UserType#deepCopy(java.lang.Object)
*/
public Object deepCopy (Object value) throws HibernateException
{
if (!UUID.class.isAssignableFrom (value.getClass ()))
{
throw new HibernateException (value.getClass ().toString () + CAST_EXCEPTION_TEXT) ;
}
UUID other = (UUID) value ;
return UUID.fromString (other.toString ()) ;
}
/*
* (non-Javadoc)
* @see org.hibernate.usertype.UserType#disassemble(java.lang.Object)
*/
public Serializable disassemble (Object value) throws HibernateException
{
return value.toString () ;
}
/*
* (non-Javadoc)
* @see org.hibernate.usertype.UserType#equals(java.lang.Object,
* java.lang.Object)
*/
public boolean equals (Object x, Object y) throws HibernateException
{
if (x == y)
return true ;
if (!UUID.class.isAssignableFrom (x.getClass ()))
{
throw new HibernateException (x.getClass ().toString () + CAST_EXCEPTION_TEXT) ;
}
else if (!UUID.class.isAssignableFrom (y.getClass ()))
{
throw new HibernateException (y.getClass ().toString () + CAST_EXCEPTION_TEXT) ;
}
UUID a = (UUID) x ;
UUID b = (UUID) y ;
return a.equals (b) ;
}
/*
* (non-Javadoc)
* @see org.hibernate.usertype.UserType#hashCode(java.lang.Object)
*/
public int hashCode (Object x) throws HibernateException
{
if (!UUID.class.isAssignableFrom (x.getClass ()))
{
throw new HibernateException (x.getClass ().toString () + CAST_EXCEPTION_TEXT) ;
}
return x.hashCode () ;
}
/*
* (non-Javadoc)
* @see org.hibernate.usertype.UserType#isMutable()
*/
public boolean isMutable ()
{
return false ;
}
/*
* (non-Javadoc)
* @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet,
* java.lang.String[], java.lang.Object)
*/
public Object nullSafeGet (ResultSet rs, String[] names, Object owner) throws HibernateException,
SQLException
{
String value = rs.getString (names[0]) ;
if (value == null)
{
return null ;
}
else
{
return UUID.fromString (value) ;
}
}
/*
* (non-Javadoc)
* @see
* org.hibernate.usertype.UserType#nullSafeSet(java.sql.PreparedStatement,
* java.lang.Object, int)
*/
public void nullSafeSet (PreparedStatement st, Object value, int index)
throws HibernateException, SQLException
{
if (value == null)
{
st.setNull (index, Types.VARCHAR) ;
return ;
}
if (!UUID.class.isAssignableFrom (value.getClass ()))
{
throw new HibernateException (value.getClass ().toString () + CAST_EXCEPTION_TEXT) ;
}
st.setString (index, value.toString ()) ;
}
/*
* (non-Javadoc)
* @see org.hibernate.usertype.UserType#replace(java.lang.Object,
* java.lang.Object, java.lang.Object)
*/
public Object replace (Object original, Object target, Object owner) throws HibernateException
{
if (!UUID.class.isAssignableFrom (original.getClass ()))
{
throw new HibernateException (original.getClass ().toString () + CAST_EXCEPTION_TEXT) ;
}
return UUID.fromString (original.toString ()) ;
}
/*
* (non-Javadoc)
* @see org.hibernate.usertype.UserType#returnedClass()
*/
@SuppressWarnings("unchecked")
public Class returnedClass ()
{
return UUID.class ;
}
/*
* (non-Javadoc)
* @see org.hibernate.usertype.UserType#sqlTypes()
*/
public int[] sqlTypes ()
{
return new int[] { Types.CHAR } ;
}
}
We are probably going to be using this UUID type for a lot of things, for example if it is a key field, there will be a corresponding column in another table.
I like one hibernate definition per file (which has so many advantages I could get another blog out of it!), so I need a new file to hold UUIDUserType
’s indirection name so that we can reuse it in our other hibernate mapping files.
It would be sensible to call it uuid or guid but this will clash with existing (built-in) indirection names so we must pick another.
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<typedef name="bsuuid"
class="uk.co.bigsoft.project.types.UUIDUserType">
</typedef>
</hibernate-mapping>
The main reason for using UUID’s is that they are unique! So now we need a generator that generates them and returns them in the form we want. Hibernate has 2 uid generators; none of which fit the bill.
The first, uuid, returns a uid in the form “aaaaaaaabbbbccccddddeeeeeeeeeeee” which is generated by hibernate and the second, guid, returns it in the form “aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee” which is generated from a call to the database.
The problem with both of these is that they return the object as a String, which means that your POJO must have the id as a String with the method signature of setId(String id)
.
Hibernate infers that because the setter for id is a String then id must be a String. We want our id to be a UUID. We don’t want to duplicate getters and setters depending on what situation we are in.
The UuidGenerator
below generates a UUID which implements the IdentifierGenerator hibernate interface and allows us to return a real UUID which travels through hibernate as a Serializable object, until it passes through UUIDUserType
(above) and ends up in our POJO’s setter as a real UUID.
package uk.co.bigsoft.project.db.types ;
import java.io.Serializable;
import java.util.UUID;
import org.hibernate.HibernateException;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.id.IdentifierGenerator;
public class UuidGenerator implements IdentifierGenerator
{
@Override
public Serializable generate (SessionImplementor session, Object parent)
throws HibernateException
{
UUID u = UUID.randomUUID () ;
return u ;
}
}
Below is an example instance of a POJO class with a UUID for an id:
package uk.co.bigsoft.project ;
import java.util.UUID;
public class MyClass
{
private UUID id ;
private String stuff ;
public void setId (UUID id)
{
this.id = id ;
}
public UUID getId ()
{
return id ;
}
public String getStuff ()
{
return stuff;
}
public void setStuff (String stuff)
{
this.stuff = stuff;
}
}
Finally we need to bring it all together,
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="uk.co.bigsoft.project.MyClass" table="my_class">
<id name="id" column="id" type="bsuuid" unsaved-value="null">
<generator class="uk.co.bigsoft.db.types.UuidGenerator" />
</id>
<property name="stuff" column="stuff" type="java.lang.String"/>
</class>
</hibernate-mapping>
This structure will work with any type of class not just UUID, the only caveat is that is must implement the Serializable interface.one-to-one
relationship in hibernate. I’ll put you out of your misery now - you can’t!
I have one central table and 2 one-to-one
relationship tables hanging off it.
When the primary table object is created hibernate must do a select (or a join) on the other tables to determine if it needs to create a proxy for the one-to-one
relationship or if it has to set the relationship object to null. Hibernate says that looking for the record in the database is the expensive part, so if it has gone to the trouble of finding it, it might as well use it.
My particular problem was that the 2 other records both contain lobs (Large OBjects), so it is not a simple case of loading a few columns. The general advice is to change the relationship to be one-to-many
. This changes the code somewhat because it means you need to return a List or a Set.
Just as a bit of extra advice; think before you call size to determine whether you call .size()
on the returned proxy to determine if there is an object to retrieve. Why? If you do, the proxy object will be hydrated to determine how many objects are in the set, thus destroying the point of the lazy loading in the first place.
The hibernate documentation suggests that this is all possible, there even appears to be options in the xml configuration file to switch on lazy loading for one-to-one
relationships, but they have apparently no effect.
Don’t get me wrong, I like the hibernate technology; but when I checked the documentation it says “TODO” - thanks! Having wasted the last week trying to figure out why this was not working, trawling the web and reading countless blogs, articles and forums I eventually found a reference in the hibernate forum which was the most help and thought I would share it with you.
I have to say that for an area that is very often miss-understood, the documentation is severely lacking. As a developer writing documentation is the most boring part of our jobs, but ironically the most important.
Anyway the most useful article I found was in the hibernate forums:
http://forum.hibernate.org/viewtopic.php?p=2380205
I hit this problem in October 2008 and my extensive research lead me to the above conclusion. If I have got it wrong then I am sorry and it proves my point about the documentation, but if I have got it right then it proves my point about the documentation ;)
If any one can shed some light on this please comment below.