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



Reply via email to