You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@openjpa.apache.org by Todd Nine <to...@spidertracks.com> on 2014/03/19 06:10:13 UTC

Using a time UUID as a sequence

Hi all,
 We're migrating from a Key/Value system to MySQL for some components of
our system for easier administration and maintenance.  As part of this
migration, we need to retain the time UUIDs that have been generated for
primary keys.  I'm having a hard time mapping this.  I have the following.

@Id
@Column( columnDefinition = "BINARY(16)", length = 16 )
private UUID id;

However this always seems to fail.  I'm on the latest MySQL version 5.6.16
GA and Open JPA 2.2.2 I've found this old thread, but it's not quite what
I'm looking for.  I'm really struggling to find the documentation on how to
declare and implement custom type converters. Converting a UUID to a binary
array of length 16 is trivial, as is creating a new UUID instance from
those bytes.  I'm just not sure how to plug in to the JPA framework to make
it happen.  Any advice would be greatly appreciated.

Thanks,
Todd

Re: Using a time UUID as a sequence

Posted by Rick Curtis <cu...@gmail.com>.
Todd -

Honestly, I don't have much experience in this area. If you are able to put
together a small unit test I'll try to take a look when I get some time.

Thanks,
Rick


On Wed, Mar 19, 2014 at 10:05 PM, Todd Nine <to...@spidertracks.com> wrote:

> Just to follow up my own email, my configuration in the persistence XML
> does work as expected.  However, I'm receiving this error.
>
> Caused by: org.apache.openjpa.lib.jdbc.ReportingSQLException: BLOB/TEXT
> column 'id' used in key specification without a key length {stmnt 992554479
> CREATE TABLE AlertAcknowlege (id BLOB NOT NULL, createTime DATETIME,
> imeiNumber VARCHAR(255), queuedDate DATETIME, statusCode INTEGER, DTYPE
> VARCHAR(255), PRIMARY KEY (id)) ENGINE = innodb} [code=1170, state=42000]
>  at
>
> org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator.wrap(LoggingConnectionDecorator.java:247)
>
>
> Here is my mapping class.
>
> **
>  * The value handler for converting com.eaio.uuid.UUID objects to byte
> arrays.
>  *
>  *
>  * @author Todd Nine
>  */
> public class UUIDValueHandler extends ByteArrayValueHandler {
>
>     @Override
>     public Object toDataStoreValue(ValueMapping vm, Object val, JDBCStore
> store) {
>
>         final byte[] data = UUIDSerializer.toBytes((com.eaio.uuid.UUID)
> val);
>
>         return super.toDataStoreValue(vm, data, store);
>
>     }
>
>
>     @Override
>     public Object toObjectValue(ValueMapping vm, Object val) {
>         byte[] data = (byte[]) val;
>
>         final UUID uuid = UUIDSerializer.fromBytes(data);
>
>         return uuid;
>     }
>
>     @Override
>     public Column[] map(ValueMapping vm, DBIdentifier name, ColumnIO io,
> boolean adapt) {
>
>         Column col = new Column();
>         col.setIdentifier(name);
>         col.setJavaType(JavaSQLTypes.BYTES);
>         //we should always be binary 16 for the uuid
>         col.setType(Types.BINARY);
>         col.setSize(UUIDSerializer.LENGTH);
>
>         return new Column[]{ col };
>     }
>
>
> }
>
> As you can see on the type, I'm definitely setting the type to binary, and
> the length to 16 for every UUID type I encounter.  Am I doing this
> incorrectly for the schema generation to work properly?
>
> Thanks,
> Todd
>
>
> On 19 March 2014 18:56, Todd Nine <to...@spidertracks.com> wrote:
>
> > Thanks for the reply Rick.  That does the trick for one field, but this
> > class is used heavily throughout the model.  If possible I'd like to
> create
> > a custom field mapping, so that every time a UUID is encountered, this
> > mapping happens automatically.    I've created a custom field mapping.
> >
> > public class UUIDValueHandler extends ByteArrayValueHandler {
> >
> >     @Override
> >     public Object toDataStoreValue(ValueMapping vm, Object val, JDBCStore
> > store) {
> >
> >         final byte[] data = UUIDSerializer.toBytes((com.eaio.uuid.UUID)
> > val);
> >
> >         return super.toDataStoreValue(vm, data, store);
> >
> >     }
> >
> >
> >     @Override
> >     public Object toObjectValue(ValueMapping vm, Object val) {
> >         byte[] data = (byte[]) val;
> >
> >         final UUID uuid = UUIDSerializer.fromBytes(data);
> >
> >         return uuid;
> >     }
> > }
> >
> > However, it's not clear to me how to configure this as a plugin via the
> > JPA configuration.  I searched through the documentation, but I can't
> find
> > any examples for how to do this.  I referenced this section.
> >
> >
> >
> http://ci.apache.org/projects/openjpa/trunk/docbook/manual.html#ref_guide_mapping_custom_field_conf
> >
> > However when I navigate to the reference of section 4 it takes me to this
> > section.
> >
> >
> >
> http://ci.apache.org/projects/openjpa/trunk/docbook/manual.html#ref_guide_mapping_defaults
> >
> > Should I define a property as follows?
> >
> > <property name="openjpa.jdbc.MappingDefaults"
> >
> value="FieldStrategies='com.eaio.uuid.UUID=com.spidertracks.aviator.dataaccess.jpa.mysql.UUIDValueHandler'"/>
> >
> >
> >
> > On 19 March 2014 08:56, Rick Curtis <cu...@gmail.com> wrote:
> >
> >> Todd -
> >>
> >> Take a look at @Externalizer/@Factory in the user manual[1]. Below is a
> >> snippet of code where I have a String field in my Entity, but the
> backing
> >> column in the DB is an int. The Externalizer/Factory methods convert
> >> values
> >> from/to the database. Let me know how this goes.
> >>
> >> Thanks,
> >> Rick
> >>
> >>     @Id
> >>
> >>
> >>
> @Externalizer("org.apache.openjpa.persistence.kernel.common.apps.RuntimeTest1.toDb")
> >>
> >>
> >>
> @Factory("org.apache.openjpa.persistence.kernel.common.apps.RuntimeTest1.fromDb")
> >>     private String intField;
> >>
> >>     public static int toDb(String val){
> >>         return Integer.valueOf(val);
> >>     }
> >>
> >>     public static String fromDb(int val) {
> >>         return String.valueOf(val);
> >>     }
> >>
> >> [1]
> >>
> >>
> http://ci.apache.org/projects/openjpa/trunk/docbook/manual.html#ref_guide_pc_extern
> >>
> >>
> >> On Wed, Mar 19, 2014 at 12:10 AM, Todd Nine <to...@spidertracks.com>
> >> wrote:
> >>
> >> > Hi all,
> >> >  We're migrating from a Key/Value system to MySQL for some components
> of
> >> > our system for easier administration and maintenance.  As part of this
> >> > migration, we need to retain the time UUIDs that have been generated
> for
> >> > primary keys.  I'm having a hard time mapping this.  I have the
> >> following.
> >> >
> >> > @Id
> >> > @Column( columnDefinition = "BINARY(16)", length = 16 )
> >> > private UUID id;
> >> >
> >> > However this always seems to fail.  I'm on the latest MySQL version
> >> 5.6.16
> >> > GA and Open JPA 2.2.2 I've found this old thread, but it's not quite
> >> what
> >> > I'm looking for.  I'm really struggling to find the documentation on
> >> how to
> >> > declare and implement custom type converters. Converting a UUID to a
> >> binary
> >> > array of length 16 is trivial, as is creating a new UUID instance from
> >> > those bytes.  I'm just not sure how to plug in to the JPA framework to
> >> make
> >> > it happen.  Any advice would be greatly appreciated.
> >> >
> >> > Thanks,
> >> > Todd
> >> >
> >>
> >>
> >>
> >> --
> >> *Rick Curtis*
> >>
> >
> >
>



-- 
*Rick Curtis*

Re: Using a time UUID as a sequence

Posted by Todd Nine <to...@spidertracks.com>.
Just to follow up my own email, my configuration in the persistence XML
does work as expected.  However, I'm receiving this error.

Caused by: org.apache.openjpa.lib.jdbc.ReportingSQLException: BLOB/TEXT
column 'id' used in key specification without a key length {stmnt 992554479
CREATE TABLE AlertAcknowlege (id BLOB NOT NULL, createTime DATETIME,
imeiNumber VARCHAR(255), queuedDate DATETIME, statusCode INTEGER, DTYPE
VARCHAR(255), PRIMARY KEY (id)) ENGINE = innodb} [code=1170, state=42000]
 at
org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator.wrap(LoggingConnectionDecorator.java:247)


Here is my mapping class.

**
 * The value handler for converting com.eaio.uuid.UUID objects to byte
arrays.
 *
 *
 * @author Todd Nine
 */
public class UUIDValueHandler extends ByteArrayValueHandler {

    @Override
    public Object toDataStoreValue(ValueMapping vm, Object val, JDBCStore
store) {

        final byte[] data = UUIDSerializer.toBytes((com.eaio.uuid.UUID)
val);

        return super.toDataStoreValue(vm, data, store);

    }


    @Override
    public Object toObjectValue(ValueMapping vm, Object val) {
        byte[] data = (byte[]) val;

        final UUID uuid = UUIDSerializer.fromBytes(data);

        return uuid;
    }

    @Override
    public Column[] map(ValueMapping vm, DBIdentifier name, ColumnIO io,
boolean adapt) {

        Column col = new Column();
        col.setIdentifier(name);
        col.setJavaType(JavaSQLTypes.BYTES);
        //we should always be binary 16 for the uuid
        col.setType(Types.BINARY);
        col.setSize(UUIDSerializer.LENGTH);

        return new Column[]{ col };
    }


}

As you can see on the type, I'm definitely setting the type to binary, and
the length to 16 for every UUID type I encounter.  Am I doing this
incorrectly for the schema generation to work properly?

Thanks,
Todd


On 19 March 2014 18:56, Todd Nine <to...@spidertracks.com> wrote:

> Thanks for the reply Rick.  That does the trick for one field, but this
> class is used heavily throughout the model.  If possible I'd like to create
> a custom field mapping, so that every time a UUID is encountered, this
> mapping happens automatically.    I've created a custom field mapping.
>
> public class UUIDValueHandler extends ByteArrayValueHandler {
>
>     @Override
>     public Object toDataStoreValue(ValueMapping vm, Object val, JDBCStore
> store) {
>
>         final byte[] data = UUIDSerializer.toBytes((com.eaio.uuid.UUID)
> val);
>
>         return super.toDataStoreValue(vm, data, store);
>
>     }
>
>
>     @Override
>     public Object toObjectValue(ValueMapping vm, Object val) {
>         byte[] data = (byte[]) val;
>
>         final UUID uuid = UUIDSerializer.fromBytes(data);
>
>         return uuid;
>     }
> }
>
> However, it's not clear to me how to configure this as a plugin via the
> JPA configuration.  I searched through the documentation, but I can't find
> any examples for how to do this.  I referenced this section.
>
>
> http://ci.apache.org/projects/openjpa/trunk/docbook/manual.html#ref_guide_mapping_custom_field_conf
>
> However when I navigate to the reference of section 4 it takes me to this
> section.
>
>
> http://ci.apache.org/projects/openjpa/trunk/docbook/manual.html#ref_guide_mapping_defaults
>
> Should I define a property as follows?
>
> <property name="openjpa.jdbc.MappingDefaults"
> value="FieldStrategies='com.eaio.uuid.UUID=com.spidertracks.aviator.dataaccess.jpa.mysql.UUIDValueHandler'"/>
>
>
>
> On 19 March 2014 08:56, Rick Curtis <cu...@gmail.com> wrote:
>
>> Todd -
>>
>> Take a look at @Externalizer/@Factory in the user manual[1]. Below is a
>> snippet of code where I have a String field in my Entity, but the backing
>> column in the DB is an int. The Externalizer/Factory methods convert
>> values
>> from/to the database. Let me know how this goes.
>>
>> Thanks,
>> Rick
>>
>>     @Id
>>
>>
>> @Externalizer("org.apache.openjpa.persistence.kernel.common.apps.RuntimeTest1.toDb")
>>
>>
>> @Factory("org.apache.openjpa.persistence.kernel.common.apps.RuntimeTest1.fromDb")
>>     private String intField;
>>
>>     public static int toDb(String val){
>>         return Integer.valueOf(val);
>>     }
>>
>>     public static String fromDb(int val) {
>>         return String.valueOf(val);
>>     }
>>
>> [1]
>>
>> http://ci.apache.org/projects/openjpa/trunk/docbook/manual.html#ref_guide_pc_extern
>>
>>
>> On Wed, Mar 19, 2014 at 12:10 AM, Todd Nine <to...@spidertracks.com>
>> wrote:
>>
>> > Hi all,
>> >  We're migrating from a Key/Value system to MySQL for some components of
>> > our system for easier administration and maintenance.  As part of this
>> > migration, we need to retain the time UUIDs that have been generated for
>> > primary keys.  I'm having a hard time mapping this.  I have the
>> following.
>> >
>> > @Id
>> > @Column( columnDefinition = "BINARY(16)", length = 16 )
>> > private UUID id;
>> >
>> > However this always seems to fail.  I'm on the latest MySQL version
>> 5.6.16
>> > GA and Open JPA 2.2.2 I've found this old thread, but it's not quite
>> what
>> > I'm looking for.  I'm really struggling to find the documentation on
>> how to
>> > declare and implement custom type converters. Converting a UUID to a
>> binary
>> > array of length 16 is trivial, as is creating a new UUID instance from
>> > those bytes.  I'm just not sure how to plug in to the JPA framework to
>> make
>> > it happen.  Any advice would be greatly appreciated.
>> >
>> > Thanks,
>> > Todd
>> >
>>
>>
>>
>> --
>> *Rick Curtis*
>>
>
>

Re: Using a time UUID as a sequence

Posted by Todd Nine <to...@spidertracks.com>.
Thanks for the reply Rick.  That does the trick for one field, but this
class is used heavily throughout the model.  If possible I'd like to create
a custom field mapping, so that every time a UUID is encountered, this
mapping happens automatically.    I've created a custom field mapping.

public class UUIDValueHandler extends ByteArrayValueHandler {

    @Override
    public Object toDataStoreValue(ValueMapping vm, Object val, JDBCStore
store) {

        final byte[] data = UUIDSerializer.toBytes((com.eaio.uuid.UUID)
val);

        return super.toDataStoreValue(vm, data, store);

    }


    @Override
    public Object toObjectValue(ValueMapping vm, Object val) {
        byte[] data = (byte[]) val;

        final UUID uuid = UUIDSerializer.fromBytes(data);

        return uuid;
    }
}

However, it's not clear to me how to configure this as a plugin via the JPA
configuration.  I searched through the documentation, but I can't find any
examples for how to do this.  I referenced this section.

http://ci.apache.org/projects/openjpa/trunk/docbook/manual.html#ref_guide_mapping_custom_field_conf

However when I navigate to the reference of section 4 it takes me to this
section.

http://ci.apache.org/projects/openjpa/trunk/docbook/manual.html#ref_guide_mapping_defaults

Should I define a property as follows?

<property name="openjpa.jdbc.MappingDefaults"
value="FieldStrategies='com.eaio.uuid.UUID=com.spidertracks.aviator.dataaccess.jpa.mysql.UUIDValueHandler'"/>



On 19 March 2014 08:56, Rick Curtis <cu...@gmail.com> wrote:

> Todd -
>
> Take a look at @Externalizer/@Factory in the user manual[1]. Below is a
> snippet of code where I have a String field in my Entity, but the backing
> column in the DB is an int. The Externalizer/Factory methods convert values
> from/to the database. Let me know how this goes.
>
> Thanks,
> Rick
>
>     @Id
>
>
> @Externalizer("org.apache.openjpa.persistence.kernel.common.apps.RuntimeTest1.toDb")
>
>
> @Factory("org.apache.openjpa.persistence.kernel.common.apps.RuntimeTest1.fromDb")
>     private String intField;
>
>     public static int toDb(String val){
>         return Integer.valueOf(val);
>     }
>
>     public static String fromDb(int val) {
>         return String.valueOf(val);
>     }
>
> [1]
>
> http://ci.apache.org/projects/openjpa/trunk/docbook/manual.html#ref_guide_pc_extern
>
>
> On Wed, Mar 19, 2014 at 12:10 AM, Todd Nine <to...@spidertracks.com> wrote:
>
> > Hi all,
> >  We're migrating from a Key/Value system to MySQL for some components of
> > our system for easier administration and maintenance.  As part of this
> > migration, we need to retain the time UUIDs that have been generated for
> > primary keys.  I'm having a hard time mapping this.  I have the
> following.
> >
> > @Id
> > @Column( columnDefinition = "BINARY(16)", length = 16 )
> > private UUID id;
> >
> > However this always seems to fail.  I'm on the latest MySQL version
> 5.6.16
> > GA and Open JPA 2.2.2 I've found this old thread, but it's not quite what
> > I'm looking for.  I'm really struggling to find the documentation on how
> to
> > declare and implement custom type converters. Converting a UUID to a
> binary
> > array of length 16 is trivial, as is creating a new UUID instance from
> > those bytes.  I'm just not sure how to plug in to the JPA framework to
> make
> > it happen.  Any advice would be greatly appreciated.
> >
> > Thanks,
> > Todd
> >
>
>
>
> --
> *Rick Curtis*
>

Re: Using a time UUID as a sequence

Posted by Rick Curtis <cu...@gmail.com>.
Todd -

Take a look at @Externalizer/@Factory in the user manual[1]. Below is a
snippet of code where I have a String field in my Entity, but the backing
column in the DB is an int. The Externalizer/Factory methods convert values
from/to the database. Let me know how this goes.

Thanks,
Rick

    @Id

@Externalizer("org.apache.openjpa.persistence.kernel.common.apps.RuntimeTest1.toDb")

@Factory("org.apache.openjpa.persistence.kernel.common.apps.RuntimeTest1.fromDb")
    private String intField;

    public static int toDb(String val){
        return Integer.valueOf(val);
    }

    public static String fromDb(int val) {
        return String.valueOf(val);
    }

[1]
http://ci.apache.org/projects/openjpa/trunk/docbook/manual.html#ref_guide_pc_extern


On Wed, Mar 19, 2014 at 12:10 AM, Todd Nine <to...@spidertracks.com> wrote:

> Hi all,
>  We're migrating from a Key/Value system to MySQL for some components of
> our system for easier administration and maintenance.  As part of this
> migration, we need to retain the time UUIDs that have been generated for
> primary keys.  I'm having a hard time mapping this.  I have the following.
>
> @Id
> @Column( columnDefinition = "BINARY(16)", length = 16 )
> private UUID id;
>
> However this always seems to fail.  I'm on the latest MySQL version 5.6.16
> GA and Open JPA 2.2.2 I've found this old thread, but it's not quite what
> I'm looking for.  I'm really struggling to find the documentation on how to
> declare and implement custom type converters. Converting a UUID to a binary
> array of length 16 is trivial, as is creating a new UUID instance from
> those bytes.  I'm just not sure how to plug in to the JPA framework to make
> it happen.  Any advice would be greatly appreciated.
>
> Thanks,
> Todd
>



-- 
*Rick Curtis*