1 2 Previous Next 23 Replies Latest reply on Mar 24, 2012 3:56 PM by suikast42

    Jboss Remoting (7.1.0.Final ) and java transient fields.

    suikast42

      Hi guys,

       

      I have some parts in my datamodel which are declerated with java transient. Not JPA Transient. For example:

      @Entity

      @Table(name = "EMPLOYEE")

      public class Employee implements Serializable, BusinessObject {

       

        @Id

        @GeneratedValue

        private Long              id;

        private String            surname;

        private String            name;

        private transient String  test             = "TEST";

      ....

      }

       

      I came in trouble with the new Jboss remoting. Because if I call getTestString() I allways get the default value of my String and not null. Here is my testcase:

       

       

        @Test

        public void test(){

          Employee emp = new Employee();

          emp.setName("EmplName");

          Assert.assertEquals("DEFAULT", emp.getTestString());

          emp.setTestString("TestNew");

          Assert.assertEquals("TestNew", emp.getTestString());

          BusinessObject empNew = service.saveGetObj(emp);

          Assert.assertNull( empNew.getTestString());  // This works in JBoss 6.1.0.Final and JBoss 5.1.0.GA but not in JBOSS 7.1.0.Final

        }

       

      So I get after call getTestString() allways my default value. But I assume that should be null.

       

      I assume that is a Bug or I'm wrong??

        • 1. Re: Jboss Remoting (7.1.0.Final ) and java transient fields.
          suikast42

          Hi it's me again,

           

          I try my test with normal object serialasation of java. That works as well. I think the problem is in Jboss remoting.

           

          Testcase with object serialisation:

           

          @Test

            public void testSerialisation(){

              Employee emp = new Employee();

              emp.setName("EmplName");

              Assert.assertEquals("DEFAULT", emp.getTestString());

              emp.setTestString("TestNew");

              Assert.assertEquals("TestNew", emp.getTestString());

           

              OutputStream fos = null;

              String filename = "test";

              try

              {

                fos = new FileOutputStream(filename);

                ObjectOutputStream o = new ObjectOutputStream(fos);

                o.writeObject(emp);

              } catch (IOException e) {

                System.err.println(e);

              } finally {

                try {

                  fos.close();

                } catch (Exception e) {

                  e.printStackTrace();

                }

              }

           

              InputStream fis = null;

              BusinessObject empNew=null;

              try

              {

                fis = new FileInputStream(filename);

                ObjectInputStream o = new ObjectInputStream(fis);

                empNew = (BusinessObject)o.readObject();

              } catch (IOException e) {

                System.err.println(e);

              } catch (ClassNotFoundException e) {

                System.err.println(e);

              } finally {

                try {

                  fis.close();

                } catch (Exception e) {

                }

              }

           

              Assert.assertNull(empNew.getTestString());

            }

          • 2. Re: Jboss Remoting (7.1.0.Final ) and java transient fields.
            ctomc

            Hi,

             

            looks like it is a bug as you found out.

            Can you please file an issue in jira, so it can attention from developers

             

            --

            tomaz

            • 3. Re: Jboss Remoting (7.1.0.Final ) and java transient fields.
              suikast42

              So if you can tell me how can I do this then I'll do it .

              • 4. Re: Jboss Remoting (7.1.0.Final ) and java transient fields.
                suikast42
                • 5. Re: Jboss Remoting (7.1.0.Final ) and java transient fields.
                  suikast42

                  I found a "clean" workarround for this problem.

                   

                  Fortunately I have a toplevel entitty for my businessmodell. So I can do a little hack for the serialisation.

                   

                  For setting the transient field to null due de deserialisation I do the thing shown below:

                   

                      // Called by the serialisation mechanisim.

                    private void readObject( ObjectInputStream ois ) throws IOException

                    {

                      try

                      {

                        ois.defaultReadObject(); // Do your stuff like you want

                        setTransientFieldsToNull(getClass());     // Set all the transient fields to null

                      }

                      catch ( ClassNotFoundException e )

                      {

                        throw new IOException( e );

                      }

                    }

                   

                   

                   

                    private void setTransientFieldsToNull(Class<?> clazz){

                      if(clazz.equals(Object.class)){

                        return;

                      }

                      for(Field field: clazz.getDeclaredFields()){

                        if(Modifier.isTransient(field.getModifiers())){

                          try {

                            field.setAccessible(true);

                            field.set(this, null);

                          } catch (Exception e) {

                            e.printStackTrace();

                          }

                        }

                      }

                      setTransientFieldsToNull(clazz.getSuperclass());

                    }

                  • 6. Re: Jboss Remoting (7.1.0.Final ) and java transient fields.
                    smarlow

                    Could you dig in a little deeper to see if this is a JPA or remoting issue.  Would it be possible to eliminate JPA from the test? 

                     

                    I'm not sure how much this would help but maybe the below code change might also show more information:

                     

                     

                     private transient String  test   =  getDefaultTestValue();
                    
                    
                    private String getDefaultTestValue() {
                    
                    
                      Thread.dumpStack();
                      return "TEST";
                    }
                    
                    
                    
                    
                    

                     

                    That should show the call stack showing the 'test' field getting initialized.

                    • 7. Re: Jboss Remoting (7.1.0.Final ) and java transient fields.
                      suikast42

                      Hi Scott,

                       

                      this is the Dump with JPA:

                       

                      10:03:22,414 ERROR [stderr] (MSC service thread 1-5) java.lang.Exception: Stack trace

                      10:03:22,414 ERROR [stderr] (MSC service thread 1-5)     at java.lang.Thread.dumpStack(Thread.java:1249)

                      10:03:22,429 ERROR [stderr] (MSC service thread 1-5)     at com.siemag.model.Employee.getDefaultTestValue(Employee.java:65)

                      10:03:22,429 ERROR [stderr] (MSC service thread 1-5)     at com.siemag.model.Employee.<init>(Employee.java:25)

                      10:03:22,429 ERROR [stderr] (MSC service thread 1-5)     at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

                      10:03:22,429 ERROR [stderr] (MSC service thread 1-5)     at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)

                      10:03:22,429 ERROR [stderr] (MSC service thread 1-5)     at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)

                      10:03:22,429 ERROR [stderr] (MSC service thread 1-5)     at java.lang.reflect.Constructor.newInstance(Constructor.java:513)

                      10:03:22,429 ERROR [stderr] (MSC service thread 1-5)     at org.hibernate.engine.internal.UnsavedValueFactory.instantiate(UnsavedValueFactory.java:46)

                      10:03:22,429 ERROR [stderr] (MSC service thread 1-5)     at org.hibernate.engine.internal.UnsavedValueFactory.getUnsavedIdentifierValue(UnsavedValueFactory.java:68)

                      10:03:22,429 ERROR [stderr] (MSC service thread 1-5)     at org.hibernate.tuple.PropertyFactory.buildIdentifierProperty(PropertyFactory.java:75)

                      10:03:22,445 ERROR [stderr] (MSC service thread 1-5)     at org.hibernate.tuple.entity.EntityMetamodel.<init>(EntityMetamodel.java:143)

                      10:03:22,445 ERROR [stderr] (MSC service thread 1-5)     at org.hibernate.persister.entity.AbstractEntityPersister.<init>(AbstractEntityPersister.java:498)

                      10:03:22,445 ERROR [stderr] (MSC service thread 1-5)     at org.hibernate.persister.entity.SingleTableEntityPersister.<init>(SingleTableEntityPersister.java:142)

                      10:03:22,445 ERROR [stderr] (MSC service thread 1-5)     at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

                      10:03:22,445 ERROR [stderr] (MSC service thread 1-5)     at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)

                      10:03:22,445 ERROR [stderr] (MSC service thread 1-5)     at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)

                      10:03:22,445 ERROR [stderr] (MSC service thread 1-5)     at java.lang.reflect.Constructor.newInstance(Constructor.java:513)

                      10:03:22,461 ERROR [stderr] (MSC service thread 1-5)     at org.hibernate.persister.internal.PersisterFactoryImpl.create(PersisterFactoryImpl.java:158)

                      10:03:22,461 ERROR [stderr] (MSC service thread 1-5)     at org.hibernate.persister.internal.PersisterFactoryImpl.createEntityPersister(PersisterFactoryImpl.java:131)

                      10:03:22,461 ERROR [stderr] (MSC service thread 1-5)     at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:345)

                      10:03:22,461 ERROR [stderr] (MSC service thread 1-5)     at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1737)

                      10:03:22,461 ERROR [stderr] (MSC service thread 1-5)     at org.hibernate.ejb.EntityManagerFactoryImpl.<init>(EntityManagerFactoryImpl.java:84)

                      10:03:22,461 ERROR [stderr] (MSC service thread 1-5)     at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:904)

                      10:03:22,461 ERROR [stderr] (MSC service thread 1-5)     at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:889)

                      10:03:22,461 ERROR [stderr] (MSC service thread 1-5)     at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:73)

                      10:03:22,476 ERROR [stderr] (MSC service thread 1-5)     at org.jboss.as.jpa.service.PersistenceUnitServiceImpl.createContainerEntityManagerFactory(PersistenceUnitServiceImpl.java:162)

                      10:03:22,476 ERROR [stderr] (MSC service thread 1-5)     at org.jboss.as.jpa.service.PersistenceUnitServiceImpl.start(PersistenceUnitServiceImpl.java:85)

                      10:03:22,476 ERROR [stderr] (MSC service thread 1-5)     at org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:1811)

                      10:03:22,476 ERROR [stderr] (MSC service thread 1-5)     at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1746)

                      10:03:22,476 ERROR [stderr] (MSC service thread 1-5)     at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)

                      10:03:22,476 ERROR [stderr] (MSC service thread 1-5)     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)

                      10:03:22,476 ERROR [stderr] (MSC service thread 1-5)     at java.lang.Thread.run(Thread.java:662)

                       

                      Dump without JPA

                      10:08:22,135 ERROR [stderr] (Remoting "ws048059" task-2) java.lang.Exception: Stack trace

                      10:08:22,135 ERROR [stderr] (Remoting "ws048059" task-2)     at java.lang.Thread.dumpStack(Thread.java:1249)

                      10:08:22,135 ERROR [stderr] (Remoting "ws048059" task-2)     at com.siemag.model.Employee.getDefaultTestValue(Employee.java:65)

                      10:08:22,135 ERROR [stderr] (Remoting "ws048059" task-2)     at com.siemag.model.Employee.<init>(Employee.java:25)

                      10:08:22,135 ERROR [stderr] (Remoting "ws048059" task-2)     at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

                      10:08:22,150 ERROR [stderr] (Remoting "ws048059" task-2)     at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)

                      10:08:22,150 ERROR [stderr] (Remoting "ws048059" task-2)     at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)

                      10:08:22,150 ERROR [stderr] (Remoting "ws048059" task-2)     at java.lang.reflect.Constructor.newInstance(Constructor.java:513)

                      10:08:22,150 ERROR [stderr] (Remoting "ws048059" task-2)     at org.jboss.marshalling.reflect.ReflectiveCreator.create(ReflectiveCreator.java:107)

                      10:08:22,150 ERROR [stderr] (Remoting "ws048059" task-2)     at org.jboss.marshalling.river.RiverUnmarshaller.doReadNewObject(RiverUnmarshaller.java:1232)

                      10:08:22,150 ERROR [stderr] (Remoting "ws048059" task-2)     at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:272)

                      10:08:22,150 ERROR [stderr] (Remoting "ws048059" task-2)     at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:209)

                      10:08:22,150 ERROR [stderr] (Remoting "ws048059" task-2)     at org.jboss.marshalling.AbstractObjectInput.readObject(AbstractObjectInput.java:37)

                      10:08:22,150 ERROR [stderr] (Remoting "ws048059" task-2)     at org.jboss.as.ejb3.remote.protocol.versionone.MethodInvocationMessageHandler.processMessage(MethodInvocationMessageHandler.java:156)

                      10:08:22,166 ERROR [stderr] (Remoting "ws048059" task-2)     at org.jboss.as.ejb3.remote.protocol.versionone.VersionOneProtocolChannelReceiver.handleMessage(VersionOneProtocolChannelReceiver.java:170)

                      10:08:22,166 ERROR [stderr] (Remoting "ws048059" task-2)     at org.jboss.remoting3.remote.RemoteConnectionChannel$5.run(RemoteConnectionChannel.java:435)

                      10:08:22,166 ERROR [stderr] (Remoting "ws048059" task-2)     at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)

                      10:08:22,166 ERROR [stderr] (Remoting "ws048059" task-2)     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)

                      10:08:22,166 ERROR [stderr] (Remoting "ws048059" task-2)     at java.lang.Thread.run(Thread.java:662)

                      • 8. Re: Jboss Remoting (7.1.0.Final ) and java transient fields.
                        suikast42

                        So I would say this is definitely an ejb-remoting isue.

                         

                        My testcode is shown below:

                         

                           // with JPA

                          @Override

                          public <T extends BusinessObject> T getById(Class<? extends T> clazz, Long id){

                            return em.find(clazz, id);

                          }

                         

                           // without JPA

                          @Override

                          public BusinessObject saveGetObjWithoutJPA(BusinessObject obj){

                            return obj;

                          }

                         

                        My testcases:

                          @Test

                          public void testJPA(){

                            Employee emp = new Employee();

                            emp.setName("EmplName");

                            Assert.assertEquals("DEFAULT", emp.getTestString());

                            emp.setTestString("TestNew");

                            Assert.assertEquals("TestNew", emp.getTestString());

                            BusinessObject empNew = service.saveGetObj(emp);

                            Assert.assertNull(empNew.getTestString());

                          }

                         

                          @Test

                          public void testWithoutJPA(){

                            Employee emp = new Employee();

                            emp.setName("EmplName");

                            Assert.assertEquals("DEFAULT", emp.getTestString());

                            emp.setTestString("TestNew");

                            Assert.assertEquals("TestNew", emp.getTestString());

                            BusinessObject empNew = service.saveGetObjWithoutJPA(emp);

                            Assert.assertNull(empNew.getTestString());

                          }

                         

                        Both goes wrong.

                        • 9. Re: Jboss Remoting (7.1.0.Final ) and java transient fields.
                          smarlow

                          You said that both are wrong, why is the JPA case not meeting what you would expect?

                           

                          For the remoting case, I'm not sure at this point but it is good to have the actual call stack showing that org.jboss.marshalling.reflect.ReflectiveCreator.create is creating a new instance, which is different than you are expecting.

                           

                          From a serialization point of view, I understand that transient fields are handled differently.  I'm not sure where the expected behavior is best documented, so links (or Java language spec section) are welcome.  This bug report mentions that the expected behaviour should be documented (not sure if that happened or where).  The following quote is from this bug report:

                           

                          Perhaps the aspect that many users find most confusing is the fact that instance field initializers for non-serializable (transient) instance fields are not executed upon deserialization, just like how constructors aren't-- perhaps this fact should be emphasized more explicitly and obviously in the appropriate documentation, so that the reported behavior is less likely to seem "unpredictable".

                           

                          Scott

                          • 10. Re: Jboss Remoting (7.1.0.Final ) and java transient fields.
                            suikast42

                            Scott Marlow schrieb:

                             

                            You said that both are wrong, why is the JPA case not meeting what you would expect?

                             

                            I expect that the transient fields are null after the (de)serialisation. That was so for the previous versions of jboss.  My testcase  "Assert.assertNull(empNew.getTestString());" is right in jboss 5 and jboss 6 environment.. But going wrong for 7.1.0.Final.

                            • 11. Re: Jboss Remoting (7.1.0.Final ) and java transient fields.
                              smarlow

                              Do you have the call stack output from AS5 or AS6 that you could share here.   For both the JPA and non-JPA tests.

                              • 12. Re: Jboss Remoting (7.1.0.Final ) and java transient fields.
                                suikast42

                                No that was As 7.1.0.Final. But the same testcase is right in As 5.1.0.GA and AS 6.1.0.Final.

                                • 13. Re: Jboss Remoting (7.1.0.Final ) and java transient fields.
                                  smarlow

                                  The output from calling Thread.dumpStack on 5.1.0.GA or 6.1.0.Final, would of been interesting.  From the point of view of comparing what happened in earlier AS releases versus now. 

                                  • 14. Re: Jboss Remoting (7.1.0.Final ) and java transient fields.
                                    smarlow

                                    I think that the rules that you can depend on for JPA, would be as follows.  Entity class fields that are tagged with @Transient, will not be persisted to the database but will be included when the entity is serialized for transfer to another (or same) Java process.  Entity class fields that are tagged with transient, will not be persisted to the database and will not be included when the entity is serialized for transfer to another Java process.

                                     

                                    My guess is that the behaviour that you saw before, was due to byte code generation that generated the entity class proxy.  If you have time to dig in deeper, I'd be interested in the results of a few more tests with AS 7.1.0.Final. 

                                     

                                    1. Set property hibernate.ejb.use_class_enhancer to true in your persistence.xml (<property name="hibernate.ejb.use_class_enhancer" value="true"/>).  This should cause each entity class to have a proxy generated for it (during deployment).  This can change other things for your application, so I only suggest this to see if it changes your JPA test result.
                                    2. Use the Hibernate 3.6.6.Final jars  instead of Hibernate 4.0.1 and see if the JPA tests results are different.  I can give more guidance on this test, if your interested in trying this.
                                    1 2 Previous Next