You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@openjpa.apache.org by Pinaki Poddar <pp...@bea.com> on 2008/05/01 01:28:32 UTC

RE: UUIDs

The observed error where a query containing a externalized field fails during parameter validation seems to be a genuine bug.

> org.apache.openjpa.persistence.ArgumentException: The parameter "0" is of type "java.util.UUID", but the declaration in the query is for type "java.lang.String".
>    at org.apache.openjpa.persistence.QueryImpl.validateParameter(QueryImpl.java:270)


Externalization of field values is a OpenJPA-specific feature and hence its usage/restrictions vis-a-vis JPA specification requires some discussion.

Here is a typical example: A field 'uuid' is declared as of type java.util.UUID but externalized as java.lang.String.

@Persistent
   @Column(nullable=false)
   @Externalizer("toString")        // non-static method
   @Factory("UUID.fromString")   // static method
   private UUID uuid;


When this field is used in query predicate and a parameter is bound, what should be the allowed runtime type of the parameter?
The delared type of the field (i.e. java.util.UUID) or the externalized type (i.e. java.lang.String) or both?


Object param = ... // what should be the runtime type of a binding parameter?
Query query = em.createQuery("SELECT a FROM External a WHERE a.uuid = ?1");
query.setParameter(1, param);

Here is snippet from Section 4.6.4.1 "Positional Parameters" of JPA 1.0 Spec:
"An input parameter evaluates to the abstract schema type of the corresponding parameter defined in the signature of the finder or select method with which the query is associated. It is the responsibility of the persistence provider to map the input parameter to the appropriate abstract schema type value".  

Subjected to our interpretaion of "evaluates", the above directive seems to suggest that the runtime type of the binding parameter can be either java.util.UUID or java.lang.String. And OpenJPA documentation also seems to agree.

However, with current implementation it may be non-trivial to validate the query parameter at JPA-façade layer for *both* types. It is rather prudent to restrict the user-supplied binding parameter be of declared type only (i.e. java.util.UUID) and not the externalized type (i.e. java.lang.String).    

However, the current code does not cover the externalized fields in either case. If the binding parameter is   java.util.UUID type, the validation break with the reported exception. A java.lang.String type binding parameter passes the validation phase but breaks later during data conversion. 



-----Original Message-----
From: Kevin Sutter [mailto:kwsutter@gmail.com] 
Sent: Wednesday, April 30, 2008 2:31 PM
To: dev@openjpa.apache.org
Subject: Re: UUIDs

Nikolas,
Fair enough.  From my understanding of these Externalizers, I would define your UUID field as follows:

   @Persistent
   @Column(nullable=false)
   @Externalizer("toString")        // non-static method
   @Factory("UUID.fromString")   // static method
   private UUID uuid;

OpenJPA should just use the UUID methods to go to and from the string presentation.  The @ElementType annotation should not be necessary since you don't seem to be processing a Collection of UUIDs.  These seem to be single instances of UUIDs.

Have you tried this particular combination?  I haven't made the connection between these changes and your specific error message, but let's make sure we're consistent with our understanding.  Thanks.

Kevin

On Wed, Apr 30, 2008 at 2:09 PM, Nikolas Everett <ni...@gmail.com> wrote:

> Kevin,
>
> Thanks for getting back to me.
>
> Thats a cool generator.  I might use that sometime.  Unfortunately, 
> the UUIDs are keys into another system.  I'm just trying to get them 
> to persist them into the database as string and load them into java as 
> UUIDs.
>
> Thanks again,
>
> --Nik
>
> On Wed, Apr 30, 2008 at 2:57 PM, Kevin Sutter <kw...@gmail.com> wrote:
>
> > :-)  Quiet doesn't mean we're not busy...  :-)
> >
> > My first thought when I read your append is why are you not just 
> > using
> the
> > built-in UUID generator that OpenJPA provides?  OpenJPA allows you 
> > to
> use
> > a
> > generator on non-id fields.  We can either generate the UUID as a 16 
> > character string or a 32 character hex value.  Would this usage 
> > suffice for you, or do you have some other requirements for the use 
> > of the externalizer?
> >
> > Here's a link to the documentation on the UUID generator:
> >
> >
> http://openjpa.apache.org/docs/latest/manual/manual.html#jpa_overview_
> meta_gen
> >
> > Kevin
> >
> > On Wed, Apr 30, 2008 at 9:49 AM, Nikolas Everett <ni...@gmail.com>
> > wrote:
> >
> > > I tried the attached message on the users list but didn't get any 
> > > response.
> > > Will someone on the dev listserve help?  I'm researching an ORM
> solution
> > > for
> > > our company, and can't in good conscience pick one with quiet
> listservs.
> > > Thanks,
> > >
> > > --Nik
> > >
> > > ---------- Forwarded message ----------
> > > From: Nikolas Everett <ni...@gmail.com>
> > > Date: Mon, Apr 28, 2008 at 5:20 PM
> > > Subject: UUIDs
> > > To: users@openjpa.apache.org
> > >
> > >
> > > I tried to search the archives and didn't find anything on this.  
> > > I'm using openjpa 1.0.2 and having problems with UUIDs backed into 
> > > postgres 8.2.
> > >
> > > I have a class like:
> > > @Entity
> > > @Table(uniqueConstraints={@UniqueConstraint(columnNames="uuid")})
> > > public class Account {
> > >    @Id
> > >    @GeneratedValue(strategy=GenerationType.IDENTITY)
> > >    private int id;
> > >
> > >    @Persistent
> > >    @Column(nullable=false)
> > >    @Externalizer("java.util.UUID.toString")
> > >    @Factory("java.util.UUID.fromString")
> > >    @ElementType(UUID.class)
> > >    private UUID uuid;
> > >
> > > ...getters and setters...
> > > }
> > >
> > > The uuid column is created as a character varying 255, which is 
> > > fine
> for
> > > now.
> > >
> > > I  have a method like this:
> > >    protected Account getAccountByUuid(UUID uuid) {
> > >        Query findAccount = this.em.createQuery("SELECT a FROM 
> > > Account
> a
> > > WHERE a.uuid = ?1");
> > >        findAccount.setParameter(1, uuid);
> > >        try {
> > >            return (Account) findAccount.getSingleResult();
> > >        } catch (NoResultException e) {
> > >            Account account = new Account();
> > >            account.setUuid(uuid);
> > >            this.em.persist(account);
> > >            return account;
> > >        }
> > >    }
> > >
> > > Which throws an exception like this:
> > > Exception in thread "main" <openjpa-1.0.2-r420667:627158 nonfatal 
> > > user
> > > error> org.apache.openjpa.persistence.ArgumentException: The 
> > > error> parameter
> > "0"
> > > is of type "java.util.UUID", but the declaration in the query is 
> > > for
> > type
> > > "java.lang.String".
> > >    at
> > >
> > >
> >
> org.apache.openjpa.persistence.QueryImpl.validateParameter(QueryImpl.j
> ava:270)
> > >    at
> > >
> > >
> >
> org.apache.openjpa.persistence.QueryImpl.validateParameters(QueryImpl.
> java:250)
> > >    at
> > org.apache.openjpa.persistence.QueryImpl.execute(QueryImpl.java:231)
> > >    at
> > >
> > >
> >
> org.apache.openjpa.persistence.QueryImpl.getSingleResult(QueryImpl.jav
> a:300)
> > >    at 
> > > com.companyname.Classname.getAccountByUuid(FetchData.java:73)
> > >
> > > This isn't the behavior documented here:
> > >
> > >
> >
> http://openjpa.apache.org/docs/latest/manual/ref_guide_pc_scos.html#d0
> e21916
> > >
> > > What can I do?
> > >
> > > Thanks in advance,
> > >
> > > --Nik
> > >
> >
>

Notice:  This email message, together with any attachments, may contain information  of  BEA Systems,  Inc.,  its subsidiaries  and  affiliated entities,  that may be confidential,  proprietary,  copyrighted  and/or legally privileged, and is intended solely for the use of the individual or entity named in this message. If you are not the intended recipient, and have received this message in error, please immediately return this by email and then delete it.