You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@openjpa.apache.org by Ryan Fogarty <rf...@adaptivemethods.com> on 2009/03/30 16:28:29 UTC

Is JPA 2 going to have something like JAXBs @XmlJavaTypeAdapter ?

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



Re: Is JPA 2 going to have something like JAXBs @XmlJavaTypeAdapter ?

Posted by Craig L Russell <Cr...@Sun.COM>.
Hi Ryan,

Your proposed addition to the JPA specification is very clean and even  
though it's late, I'd say it's worth considering.

Craig

On Mar 30, 2009, at 9:54 AM, Ryan Fogarty wrote:

> 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 (jsr-317-comments@jcp.org) 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 <rfogarty@adaptivemethods.com 
>>  <ma...@adaptivemethods.com>> 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
>>
>>
>>

Craig L Russell
Architect, Sun Java Enterprise System http://db.apache.org/jdo
408 276-5638 mailto:Craig.Russell@sun.com
P.S. A good JDO? O, Gasp!


Re: Is JPA 2 going to have something like JAXBs @XmlJavaTypeAdapter ?

Posted by Ryan Fogarty <rf...@adaptivemethods.com>.
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 (jsr-317-comments@jcp.org) 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 
> <rfogarty@adaptivemethods.com <ma...@adaptivemethods.com>> 
> 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
>
>
>

Re: Is JPA 2 going to have something like JAXBs @XmlJavaTypeAdapter ?

Posted by Jeremy Bauer <te...@gmail.com>.
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
<rf...@adaptivemethods.com>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
>
>
>