openjpa-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Craig L Russell <Craig.Russ...@Sun.COM>
Subject Re: Does OpenJPA replace Collections?
Date Thu, 09 Apr 2009 18:13:04 GMT
Hi Paul,

On Apr 9, 2009, at 9:40 AM, Paul Copeland wrote:

> Couple of clarifications -
>
> A lazily loaded FIELD ACCESS collection is a null value when  
> initially accessed if the Collection is EMPTY (I said "null"  
> incorrectly below).

My comment below was intended to compare your "if null then  
initialize" paradigm with my "initialize to an empty collection during  
construction". So if the first time you access the collection it is  
null your code sets the value to an empty collection. My recommended  
code would never encounter a null collection.
>
> The test I have shows this behavior for a newly persisted Entity  
> during the same transaction where em.persist(entity) is called. This  
> is with a LAZY loaded collection.

During persist, the provider should not replace fields. Replacing  
fields behavior should happen at commit (flush) time. So if you never  
explicitly initialize a field, it should have its Java default value  
until flush.

If you're talking about wrapping the persistent collection with an  
unmodifiable collection then you're talking about adding more objects.  
I thought you were trying to avoid any object construction?

In some applications there is a difference between an empty collection  
and a null collection. There are properties that allow that behavior  
to be implemented as well, although that's non-standard and a bit more  
complicated.

It might be easier to look at a test case because I think we're  
talking past each other.

Craig
>
>
> On 4/9/2009 9:26 AM, Paul Copeland wrote:
>> Hi Craig -
>>
>> My experience is not what you are describing.  A lazily loaded  
>> FIELD ACCESS collection is a null value when initially accessed if  
>> the Collection is null (possibly a PROPERTY ACCESS collection  
>> behaves differently as mentioned by Pinaki , I haven't tested that).
>>
>> To repeat what is below -
>>
>>                    getMyPcList()
>>
>> returns null if the Collection is empty unless you initialize the  
>> value with "new ArrayList()".  This is what my testing shows with  
>> 1.2.1 - I wish it weren't this way since that might it make it  
>> possible to use the Collections.unmodifiedList() idiom (as it is  
>> that idiom has unreliable behavior).   If the experts are pretty  
>> sure that I am wrong about this then I definitely want to  
>> investigate it further.  I'd like to hear more.
>>
>> I don't think you have given a reason to require initializing the  
>> Collection at construction time or at first access -- there are  
>> reasonable aesthetic and performance arguments either way.
>>
>> - Paul
>>
>>
>> On 4/9/2009 7:01 AM, Craig L Russell wrote:
>>> Hi Paul,
>>>
>>> I like to think of entities as POJOs first, so I can test them  
>>> without requiring them to be persistent. So if you want code to be  
>>> able to add elements to collections, the collections must not be  
>>> null.
>>>
>>> If you construct the field as null and then "lazily" instantiate  
>>> an empty collection, then anyway you end up with an empty  
>>> collection the first time you access the field. And constructing  
>>> an empty collection should not be even a blip on your performance  
>>> metric.
>>>
>>> Considering everything, I still recommend that you instantiate an  
>>> empty collection when you construct an entity.
>>>
>>> Craig
>>>
>>> On Apr 8, 2009, at 10:21 AM, Paul Copeland wrote:
>>>
>>>> Pinaki -
>>>>
>>>> I tried your suggestion of not initializing the value of myPcList  
>>>> and I get a null pointer exception when adding to an empty list.
>>>>
>>>> I noticed your example was for Property access and Russell (and  
>>>> I) were talking about Field access.  Do you agree that it is  
>>>> necessary to initialize an empty list when using Field access?
>>>>
>>>> On Craig's advice to always construct a new ArrayList(), why is  
>>>> that necessary instead of just constructing it in the getter when  
>>>> it tests to null?  Otherwise you are constructing an ArrayList  
>>>> that is unnecessary when the List is NOT empty (usually) and also  
>>>> unnecessary in the case of LAZY loading if the List is never  
>>>> accessed (perhaps also a frequent case).  In some applications  
>>>> you might create lots of these objects and normal optimization is  
>>>> to avoid calling constructors unnecessarily.  Just want to be  
>>>> clear about whether it is necessary.
>>>>
>>>> - Paul
>>>>
>>>> On 4/8/2009 9:43 AM, Paul Copeland wrote:
>>>>> Thanks Pinaki -
>>>>>
>>>>> I think you are saying that at some point the proxy object does  
>>>>> replace the local List.  Is that right?
>>>>>
>>>>> I have seen that model - if (myPcList == null) myPcList = new  
>>>>> ArrayList() - in various examples (not sure where now).  Thanks  
>>>>> for clearing that up.  But then Craig Russell contradicts you in  
>>>>> his reply (below) where he recommends always initializing the  
>>>>> Collection in the constructor (which seems like a performance  
>>>>> anti-pattern of wasted constructor calls since usually it will  
>>>>> be replaced by the proxy).   Are you and Craig saying opposite  
>>>>> things here?
>>>>>
>>>>> In my testing when the List is empty - (myPcList == null) - does  
>>>>> indeed evaluate to true.
>>>>>
>>>>>             getMyPcList().add(new MyPcObject())
>>>>>
>>>>> Therefore I thought the above would cause a null pointer  
>>>>> exception when the List is empty.  You say that won't happen so  
>>>>> I'll give it a try!
>>>>>
>>>>> - Paul
>>>>>
>>>>>
>>>>> On 4/8/2009 3:16 AM, Pinaki Poddar wrote:
>>>>>> Hi,
>>>>>> According to JPA spec:
>>>>>> "If there are no associated entities for a multi-valued  
>>>>>> relationship of an entity fetched from the database,
>>>>>> the persistence provider is responsible for returning an empty  
>>>>>> collection as the value of the relationship."
>>>>>>
>>>>>> That is what OpenJPA does. So the application do not need to  
>>>>>> return an empty list for a null (initialized) list.
>>>>>>
>>>>>> OpenJPA proxies all returned collections. So application code  
>>>>>> can simply do the following
>>>>>>
>>>>>> // In the domain class
>>>>>> private List<MyPcObject> myPcList = null; // never explictly
 
>>>>>> initialized
>>>>>>
>>>>>> @OneToMany (mappedBy="ownerSide", fetch=FetchType.LAZY,   
>>>>>> cascade=CascadeType.PERSIST)
>>>>>> public  List<Promotion> getMyPcList()  {
>>>>>>     return myPcList; // return as it is
>>>>>> }
>>>>>>
>>>>>> // In the application
>>>>>> List<Promotion> list = owner.getMyPcList();
>>>>>> assertNotNull(list);
>>>>>> assertTrue(java.util.List.class.isInstance(list));
>>>>>> assertNotSame(java.util.ArrayList.class, list.getClass());
>>>>>> list.add(new MyPcObject());
>>>>>> owner.setMyPcList(list);
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> On Apr 7, 2009, at 11:10 PM, Paul Copeland wrote:
>>>>>>
>>>>>>
>>>>>>> Can OpenJPA replace a Collection when it is loaded?
>>>>>>>
>>>>>>> With the code below when the list is initially empty you need
 
>>>>>>> to  create a List (ArrayList) so you can add elements to it.
 
>>>>>>> When I  persisted new objects on the ManyToOne side and added
 
>>>>>>> them to the  List that worked.  But the first time the List 

>>>>>>> was loaded it seemed  to replace my ArrayList with the newly
 
>>>>>>> loaded data and made an older  reference to the ArrayList  
>>>>>>> stale (no longer updated when more  elements were added to  
>>>>>>> myPcList).  This was all in one transaction.
>>>>>>>
>>>>>>> So now I wonder if the initial null List is a special case or
 
>>>>>>> if  OpenJPA might replace the Collection anytime it decides to
 
>>>>>>> load it  again.  Anyone know the answer?
>>>>>>>
>>>>>>
>>>>>> If the list is persistent and the class is enhanced, the  
>>>>>> collection  will always reflect what's in the database.
>>>>>>
>>>>>>> If I don't create an initial ArrayList how can I add elements
 
>>>>>>> when  the List is empty?
>>>>>>>
>>>>>>
>>>>>> I'd recommend always having a non-empty list. Initialize it in  
>>>>>> the  constructor to an empty list and don't check it after that.
>>>>>>
>>>>>> Here's what it would look like:
>>>>>>
>>>>>>> @OneToMany (mappedBy="ownerSide", fetch=FetchType.LAZY,   
>>>>>>> cascade=CascadeType.PERSIST)
>>>>>>> private List<MyPcObject> myPcList = new ArrayList<MyPcObject>();
>>>>>>>
>>>>>>> List<Promotion> getMyPcList()
>>>>>>> {
>>>>>>>    return myPcList;
>>>>>>> }
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>> Craig
>>>>>> 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!
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> -----
>>>>>> Pinaki Poddar                      http://ppoddar.blogspot.com/
>>>>>>                                     http://www.linkedin.com/in/pinakipoddar
>>>>>> OpenJPA PMC Member/Committer
>>>>>> JPA Expert Group Member
>>>>>>
>>>>>
>>>>>
>>>>>
>>>>
>>>
>>> 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!
>>>
>>
>>
>>
>

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!


Mime
View raw message