Hi Jeremy,
I really appreciate your response; it's good to know there is a
workaround for OpenJPA (as I understand it, Hibernate can also do this
as part of its proprietary interface). I just sent an 11th hour comment
to the JSR317 committee ([email protected]) regarding the issue.
Below is a copy of that email. I suspect that my solution is overly
simplified but might get the experts thinking about a proper solution.
Thanks again for your response,
Ryan
-- email to jsr 317:
Dear JSR 317 committee,
JAXB has a simple and powerful annotation type @XmlJavaTypeAdapter
that provides an adapter class to convert some opaque class type to
something that is more easily JAXB annotated to marshall/unmarshall
to/from XML.
Seems like a massive oversight of the JPA spec. For instance, I
cannot do the simplest thing such as make JPA embed a UUID as a varchar
in a table, instead it insists on serializing to byte[].
I would propose that 2 annotations are created one for an Entity adapter
and another for an Embeddable.
public @interface EntityAdapter {
Class<? extends PersistentTypeAdapter> value();
}
public @interface EmbeddedAdapter {
Class<? extends PersistentTypeAdapter> value();
}
public interface PersistentTypeAdapter<PersistentType,BoundType> {
PersistentType marshall(BoundType v);
BoundType unmarshall(PersistentType v);
}
Example Usage:
@Entity
public class Foo {
//...
public static class UuidAsVarchar implements
PersistentTypeAdapter<String,UUID> {
public String marshall(UUID v) { return v != null ? v.toString() :
null; }
public UUID unmarshall(String v) { return v != null ?
UUID.fromString(v) : null; }
}
@EmbeddedAdapter(UuidAsVarchar.class)
private UUID uid;
//...
}
Please extrapolate on @EntityAdapter usage. Obviously it would adapt to
a class marked as @Entity.
Jeremy Bauer wrote:
Ryan,
I agree, this would be a useful feature to have standardized by the
JPA specification. My guess is that it would be too late to try to
get something into JPA 2.0, but one could recommend this feature for
inclusion in a future version of the spec. Pinaki and Kevin (cc'd)
participate in the expert group so they may have recommendations for
submitting feature requests.
Currently, you can do the conversion yourself within your business
logic (or create separate entities or embeddables for the mappings),
which can result in an indirect and sometimes quirky OR mapping.. or
you can use OpenJPA's @Strategy extension to specify a custom value
mapping handler. Here is an example handler for UUID:
package strat;
import java.util.UUID;
import org.apache.openjpa.jdbc.kernel.JDBCStore;
import org.apache.openjpa.jdbc.meta.ValueMapping;
import org.apache.openjpa.jdbc.meta.strats.AbstractValueHandler;
import org.apache.openjpa.jdbc.schema.Column;
import org.apache.openjpa.jdbc.schema.ColumnIO;
import org.apache.openjpa.meta.JavaTypes;
public class UUIDValueHandler extends AbstractValueHandler {
public Column[] map(ValueMapping vm, String name, ColumnIO io,
boolean adapt) {
Column col = new Column();
col.setName(name);
col.setJavaType(JavaTypes.STRING);
return new Column[]{ col };
}
public boolean isVersionable() {
return true;
}
/**
* Convert the object value to its datastore equivalent.
*/
public Object toDataStoreValue(ValueMapping vm, Object val,
JDBCStore store) {
if (val == null)
return null;
UUID uuid = (UUID) val;
return uuid.toString();
}
/**
* Convert the datastore value to its object equivalent.
*/
public Object toObjectValue(ValueMapping vm, Object val) {
if (val == null)
return null;
String uuidStr = (String)val;
return UUID.fromString(uuidStr);
}
}
@Entity
public class EntityA {
...
@Strategy("strat.UUIDValueHandler")
private UUID uuid;
...
}
Using this custom value handler, UUID will be mapped internally
to/from a string type. In addition, the schema factory (if used) will
create the appropriate database column type(s). The OpenJPA unit test
suite has an additional example usage of @Strategy which maps an
object to/from multiple database columns. Search for @Strategy in
org.apache.openjpa.persistence.jdbc.annotations.NonstandardMappingEntity.
hth,
-Jeremy
On Mon, Mar 30, 2009 at 9:28 AM, Ryan Fogarty
<[email protected] <mailto:[email protected]>>
wrote:
I use @XmlJavaTypeAdapter a lot to manipulate our data model for
classes
that just don't naturally fit into an XML model (like custom
containers
and the sort). Seems to be one of the most intuitive and powerful
tools
in JAXBs toolbox but I can't find anything like it in JPA 1 or 2.
For instance, I can't seem to do the simplest thing with JPA such as
take a java.util.UUID and have OpenJPA map it into a STRING.
It looks like there is no chance of getting this into JPA 2 since they
are in final draft. I just can't imagine such a useful tool *not*
existing in a powerful API like JPA, so what gives? Have I missed
something fundamental?
Thank you,
Ryan