Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » EclipseLink » Be wary of transient nested inner class members(Event hough you can have transient data members which are from a transient inner class type you must explicitly reinitialize them PostLoad)
Be wary of transient nested inner class members [message #659721] Tue, 15 March 2011 10:59 Go to next message
J F is currently offline J F
Messages: 242
Registered: July 2009
Senior Member
I have Java 1.6 b24, Glassfish 3.1, eclipse heliosee, and eclipselink ( indirectly ) 2.2.?

I have an entity:
package uk.co.his.experiment;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.PostLoad;
import javax.persistence.Transient;

@Entity
public class LostOuter {
	@Id
	private Long id;
	
	@ElementCollection
	private List<String> commentsA = new ArrayList<String>();
	
	@ElementCollection
	private List<String> commentsB = new ArrayList<String>();
	
	public LostOuter() 
	{
		System.err.println("Constructing a LostOuter");
		commentsAWrapper = new ConfusedInnerA();
		commentsBWrapper = new ConfusedInnerB();
	}
	
	@Transient
	private transient ConfusedInnerA commentsAWrapper = new ConfusedInnerA();
	
	private class ConfusedInnerA
	{
		void addComment(String comment)
		{
			commentsA.add(comment);
		}
		
		LostOuter getOuter() { return LostOuter.this; }
	}
	
	@SuppressWarnings("unused")
	@PostLoad
	private void postLoadStitchUp()
	{
		commentsAWrapper = new ConfusedInnerA();
	}
	
	@Transient
	private transient ConfusedInnerB commentsBWrapper = new ConfusedInnerB();
	
	private class ConfusedInnerB
	{
		void addComment(String comment)
		{
			commentsB.add(comment);
		}
		
		LostOuter getOuter() { return LostOuter.this; }
	}
	
	public void addComment(String comment)
	{
		commentsAWrapper.addComment(comment);
		commentsBWrapper.addComment(comment);
	}
	
	public String getCurrentComments()
	{
		StringBuilder str = new StringBuilder();
		
		if(commentsAWrapper.getOuter() != this)
		{
			str.append("Oh no! what has happened to my commentsAWrapper?\n");
		}
		if(commentsBWrapper.getOuter() != this)
		{
			str.append("Oh no! what has happened to my commentsBWrapper?\n");
		}
		str.append("commentsA:\n");
		for (String comment : commentsA) {
			str.append("\t" + comment + "\n");
		}
		str.append("commentsB:\n");
		for (String comment : commentsB) {
			str.append("\t" + comment + "\n");
		}
		str.append("==========================\n");
		return str.toString();
	}
	
	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}
}


The following is the persistence.xml;
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="ExperimentjndiPU" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>ExperimentDB</jta-data-source>
<properties/>
</persistence-unit>
</persistence>


The following is the trace in server.log ( from eclipse console );



INFO: uk.co.his.experiment.LostOuter actually got transformed
INFO: uk.co.his.experiment.Person actually got transformed
INFO: Instantiated an instance of org.hibernate.validator.engine.resolver.JPATraversableResolv er.

INFO: EclipseLink, version: Eclipse Persistence Services - 2.2.0.v20110202-r8913
SEVERE: Constructing a LostOuter
SEVERE: Constructing a LostOuter
INFO: file:/C:/Users/Administrator/workspace/glassfish31eclipsedef aultdomain/eclipseApps/ExperimentEAR/lib/ExperimentEARmodel. jar/_ExperimentjndiPU login successful
SEVERE: Constructing a LostOuter
SEVERE: Test3 results====
SEVERE: commentsA:
Fist ever comment
commentsB:
Fist ever comment
==========================

SEVERE: Test4 results====
SEVERE: Oh no! what has happened to my commentsBWrapper?
commentsA:
Fist ever comment
Comment added next
commentsB:
Fist ever comment
==========================


SEVERE: Constructing a LostOuter
SEVERE: Test5 results====
SEVERE: commentsA:
Fist ever comment
Comment added next
commentsB:
Fist ever comment
Comment added next
==========================

Thus commentsBWrapper appears to point to another outer after reloading.

I assume this is not a bug; transient state is not guaranteed after load. I have submitted this message because I have been told that a previous combination of glassfish/java/eclipselink did not do this, and though it might help others.



Re: Be wary of transient nested inner class members [message #660824 is a reply to message #659721] Mon, 21 March 2011 19:24 Go to previous message
James Sutherland is currently offline James Sutherland
Messages: 1939
Registered: July 2009
Location: Ottawa, Canada
Senior Member

EclipseLink enables a shared cache by default. This shared cache can either support maintaining transient variables, or not.

If weaving is used, the shared cache objects are cloned to/from the persistence context, thus preserving the state of transient variables.

If weaving is not used, then new instances are created in the persistence context, and the non-transient state (only) is copied from the shared object.

So, if you don't want transients cached, then you can disable internal weaving ("eclipselink.weaving.internal"="false"), this will still allow weaving for LAZY and change tracking.

You could also disable the shared cache, or disable weaving entirely, or configure the CopyPolicy of your Entity, or use the DescriptorEvent postClone/postMerge.


James : Wiki : Book : Blog : Twitter
Previous Topic:SerializationHelper.desserialize ClassNotFound
Next Topic:Migrating toplink to eclipselink
Goto Forum:
  


Current Time: Thu Sep 18 08:02:41 GMT 2014

Powered by FUDForum. Page generated in 0.04429 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software