[ 
https://issues.apache.org/jira/browse/OPENJPA-1854?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13845733#comment-13845733
 ] 

Heath Thomann commented on OPENJPA-1854:
----------------------------------------

It has recently came to my attention that this JIRA is still open, and 
furthermore the details of a solution not documented.  Let me do so now and 
explain the conclusion myself and Fay Wang came up with when working with a few 
customers on this issue.  Basically the solution can be made via user code as 
I'll explain in a moment and is not a bug in OpenJPA code.  I was a bit 
premature in opening a JIRA and assuming their was a bug in OpenJPA code.  Let 
me first state that OPENJPA-1501 fixed an issue where a (single) Primay Key 
defined as a String contained trailing white space.  In this case, OpenJPA 
knows the type of the field (String), and has options available to remove 
trailing white space.  As such, a decision was made in the JIRA to strip the 
trailing white space from a String PK.  This has been the solution since 
OpenJPA 2.0.x.  In this JIRA, I assumed that the issue was similar and that 
OpenJPA could remove trailing white space from compound PKs, such as 
@EmbeddedId.  However, in this case OpenJPA has less control over these 
objects, or I should say the fields contained within them (these are opaque 
object from OpenJPA's point of view).  Furthermore, it is likely that any 
trailing white space for String fields in these objects are either a) put there 
by the user, or b) represents what is in the database.  That is, for #a, when a 
user creates an @Embeddable, it is possible they may add trailing white space 
to String fields.  OpenJPA has no control over this.  So for a finder method 
where a user passes in an @Embeddable, OpenJPA simply uses whatever the user 
gives the finder.  If the user pads a String field with white space, then that 
is what is used by OpenJPA.  One customer may argue OpenJPA should attempt to 
remove white space, while another may find that problematic.  For #b, if an 
@Embeddable's string fields are mapped to a char field in the database, most 
(all?) databases will return a string padded with white space up to the length 
of a char (e.g. for a char(10), and string 'test', the database will return 
'test      ' - a string with 6 white spaces).  This is likely not the case if 
the field is mapped to a varchar.  So if a user executes a query to retrieve an 
entity with an @EmbeddedId, and if the @Embeddable's string fields are mapped 
to a char field in the database, the resultant @Embeddable's string field will 
contain trailing white space up to the length of the char.  Again, this is out 
of OpenJPA's control and is simply a representation of what is in the database. 
 Obviously a solution is to use a varchar rather than char to avoid trailing 
white space.  :)  
Having said all of that, the fix here is simple and can be performed in user 
code by doing one of the following two options:  

1) Permanently remove trailing white space from within the EmbeddableId's 
constructor AND setter methods.                          
2) Permanently remove trailing white space from within the EmbeddableId's 
equals AND hashCode methods.                             

As an example, if you look at the test I had provided in the JIRA 
(OPENJPA-1854-1.2.x.test), to allow the test to work we would remove the white 
space as follows:

import org.apache.commons.lang.StringUtils;
....
        public ObjectIDEntityPK(String name, String version) {
                super();
                this.name = (name == null ? name : 
StringUtils.stripEnd(name,null));
                this.version = (version == null ? version : 
StringUtils.stripEnd(version,null)) ;
        }       

        public void setName(String name) {
                this.name = (name == null ? name : 
StringUtils.stripEnd(name,null));
        }

        public void setVersion(String version) {
                this.version = (version == null ? version : 
StringUtils.stripEnd(version,null));
        }

        public int hashCode() {
                name = StringUtils.stripEnd(name,null);
                version = StringUtils.stripEnd(version,null);
                
                final int prime = 31;
                int result = 1;
                result = prime * result + ((name == null) ? 0 : 
name.hashCode());
                result = prime * result + ((version == null) ? 0 : 
version.hashCode());
                return result;
        }

        public boolean equals(Object obj) {
                name = StringUtils.stripEnd(name,null);
                version = StringUtils.stripEnd(version,null);
                
                if (this == obj)
                        return true;
                if (obj == null)
                        return false;
                if (getClass() != obj.getClass())
                        return false;
                ObjectIDEntityPK other = (ObjectIDEntityPK) obj;
                other.name = StringUtils.stripEnd(other.name,null);
                other.version = StringUtils.stripEnd(other.version,null);
                
                if (name == null) {
                        if (other.name != null)
                                return false;
                } else if (!name.equals(other.name))
                        return false;
                if (version == null) {
                        if (other.version != null)
                                return false;
                } else if (!version.equals(other.version))
                        return false;
                return true;
        }


Thanks,

Heath Thomann

> A 'find' or 'query' may return multiple instances of Entities which contain 
> Embeddables, where the Embeddables use String identities, if the id value has 
> trailing spaces.
> --------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: OPENJPA-1854
>                 URL: https://issues.apache.org/jira/browse/OPENJPA-1854
>             Project: OpenJPA
>          Issue Type: Bug
>          Components: kernel
>    Affects Versions: 1.2.2, 1.3.0, 2.0.0
>            Reporter: Heath Thomann
>            Assignee: Heath Thomann
>         Attachments: OPENJPA-1854-1.2.x.test
>
>
> This issue is very similar to that of OPENJPA-1501, with one twist.......I've 
> found that when you have an Embeddable, which has Strings as the keys/ids, 
> openJPA code puts the Embeddable into an ObjectID by design, rather than a 
> StringID....recall, the fix to OJ1501 was to strip white space from the end 
> of a user's String key when that String was placed into a StringID.  So, the 
> strings in an Embeddable would also need to be stripped, just as was done in 
> OJ-1501, but unfortunately it would seem to be harder to do so for 
> Embeddables since openJPA code doesn't necessarily know what types are 
> contained in the Embed.
> I've created a JUnit test case which has three test methods.  The test is 
> attached here.



--
This message was sent by Atlassian JIRA
(v6.1.4#6159)

Reply via email to