Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8013416

Java Bean Persistence with XMLEncoder

    Details

    • Type: Bug
    • Status: Resolved
    • Priority: P3
    • Resolution: Fixed
    • Affects Version/s: 7u4
    • Fix Version/s: 8
    • Component/s: client-libs
    • Labels:
    • Subcomponent:
    • Resolved In Build:
      b93
    • OS:
      windows_7

      Backports

        Description

        FULL PRODUCT VERSION :
        java version " 1.7.0_17 "
        Java(TM) SE Runtime Environment (build 1.7.0_17-b02)
        Java HotSpot(TM) 64-Bit Server VM (build 23.7-b01, mixed mode)

        ADDITIONAL OS VERSION INFORMATION :
        Microsoft Windows [Version 6.1.7601]

        EXTRA RELEVANT SYSTEM CONFIGURATION :
        The following jar files are required: guava-14.0.1.jar and junit-4.10.jar. They are available at https://code.google.com/p/guava-libraries/ and https://github.com/junit-team/junit/wiki

        A DESCRIPTION OF THE PROBLEM :
        Encoding and decoding of a valid Java Bean, containing a com.google.common.collect.HashMultimap, fails. The error results from an issue in com.sun.beans.finder.MethodFinder.findMethod. The HashMultimap class inherits it's " put " method from the package private implementation in: StandardSetMultimap (and above). But that method isn't callable as the class that declares it isn't public. What the FindMethod method should do is find the public method from the Multimap interface and return that - since that is the only method that can be called without special privileges.

        REGRESSION. Last worked in version 7

        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        1) compile the unit test
        javac -cp guava-14.0.1.jar;junit-4.10.jar;. XmlEncoderTest.java

        2) run the unit test
        java -cp guava-14.0.1.jar;junit-4.10.jar;. org.junit.runner.JUnitCore XmlEncoderTest

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        The unit test should produce a valid XML file containing the following:

        <?xml version= " 1.0 " encoding= " UTF-8 " ?>
        <java version= " 1.7.0_17 " class= " java.beans.XMLDecoder " >
         <object class= " XmlEncoderTest$SomeBean " >
          <void property= " stateMap " >
           <object class= " com.google.common.collect.HashMultimap " method= " create " >
            <void method= " put " >
             <string>pz3</string>
             <string>pz4</string>
            </void>
            <void method= " put " >
             <string>pz1</string>
             <string>pz2</string>
            </void>
           </object>
          </void>
         </object>
        </java>

        The unit test should then decode the XML into a SomeBean object contains a HashMultimap with 2 entries (pz1,pz2) and (pz3,pz4).
        ACTUAL -
        The unit test produces a valid XML file; however, the following statements are written to output. Additionally, the decode SomeBean object's HashMultimap contains no entries.

        .java.lang.Exception: Encoder: discarding statement HashMultimap.put( " pz3 " , " pz4
         " );
        Continuing ...
        java.lang.Exception: Encoder: discarding statement HashMultimap.put( " pz1 " , " pz2 "
        );
        Continuing ...
        java.lang.NoSuchMethodException: <unbound>=HashMultimap.put( " pz3 " , " pz4 " );
        Continuing ...
        java.lang.NoSuchMethodException: <unbound>=HashMultimap.put( " pz1 " , " pz2 " );
        Continuing ...

        ERROR MESSAGES/STACK TRACES THAT OCCUR :
        JUnit version 4.10
        .java.lang.Exception: Encoder: discarding statement HashMultimap.put( " pz3 " , " pz4
         " );
        Continuing ...
        java.lang.Exception: Encoder: discarding statement HashMultimap.put( " pz1 " , " pz2 "
        );
        Continuing ...
        java.lang.NoSuchMethodException: <unbound>=HashMultimap.put( " pz3 " , " pz4 " );
        Continuing ...
        java.lang.NoSuchMethodException: <unbound>=HashMultimap.put( " pz1 " , " pz2 " );
        Continuing ...
        E
        Time: 0.308
        There was 1 failure:
        1) testEncoding(XmlEncoderTest)
        java.lang.AssertionError
                at org.junit.Assert.fail(Assert.java:92)
                at org.junit.Assert.assertTrue(Assert.java:43)
                at org.junit.Assert.assertTrue(Assert.java:54)
                at XmlEncoderTest.testEncoding(XmlEncoderTest.java:46)
                at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
                at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
                at java.lang.reflect.Method.invoke(Unknown Source)
                at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(Framework
        Method.java:45)
                at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCal
        lable.java:15)
                at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMe
        thod.java:42)
                at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMet
        hod.java:20)
                at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
                at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRun
        ner.java:68)
                at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRun
        ner.java:47)
                at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
                at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
                at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
                at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
                at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
                at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
                at org.junit.runners.Suite.runChild(Suite.java:128)
                at org.junit.runners.Suite.runChild(Suite.java:24)
                at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
                at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
                at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
                at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
                at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
                at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
                at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
                at org.junit.runner.JUnitCore.run(JUnitCore.java:136)
                at org.junit.runner.JUnitCore.run(JUnitCore.java:117)
                at org.junit.runner.JUnitCore.runMain(JUnitCore.java:98)
                at org.junit.runner.JUnitCore.runMainAndExit(JUnitCore.java:53)
                at org.junit.runner.JUnitCore.main(JUnitCore.java:45)


        REPRODUCIBILITY :
        This bug can be reproduced always.

        ---------- BEGIN SOURCE ----------
        import static org.junit.Assert.*;
         
        import java.beans.DefaultPersistenceDelegate;
        import java.beans.Encoder;
        import java.beans.Expression;
        import java.beans.Statement;
        import java.beans.XMLDecoder;
        import java.beans.XMLEncoder;
        import java.io.FileInputStream;
        import java.io.FileOutputStream;
        import java.util.Map;
         
        import org.junit.Test;
         
        import com.google.common.collect.HashMultimap;
         
        public class XmlEncoderTest {
         
            @Test
            public void testEncoding() throws Exception {
         
                // create the bean
                SomeBean sb = new SomeBean();
         
                // add some data
                HashMultimap<String, String> stateMap = HashMultimap.create();
                stateMap.put( " pz1 " , " pz2 " );
                stateMap.put( " pz3 " , " pz4 " );
         
                sb.setStateMap(stateMap);
         
                String fileName = " myXMLFile.xml " ;
                // encode as xml
                FileOutputStream os = new FileOutputStream(fileName);
                XMLEncoder encoder = new XMLEncoder(os);
                encoder.setPersistenceDelegate(HashMultimap.class, new CustomPersistenceDelegate());
                encoder.writeObject(sb);
                encoder.close();
         
                // decode the xml
                XMLDecoder decoder = new XMLDecoder(new FileInputStream(fileName));
                Object deSerializedObject = decoder.readObject();
                assertNotNull(deSerializedObject);
         
                HashMultimap<String, String> map = ((SomeBean) deSerializedObject).getStateMap();
                assertTrue(map.containsKey( " pz1 " ));
                assertTrue(map.containsKey( " pz3 " ));
         
            }
         
            static class CustomPersistenceDelegate extends DefaultPersistenceDelegate {
                @Override
                protected Expression instantiate(Object oldInstance, Encoder out) {
                    return new Expression(oldInstance, oldInstance.getClass(), " create " , null);
                }
         
                @Override
                protected void initialize(Class<?> type, Object oldInstance, Object newInstance, Encoder out) {
                    super.initialize(type, oldInstance, newInstance, out);
         
                    com.google.common.collect.HashMultimap<String, String> m = (com.google.common.collect.HashMultimap) oldInstance;
         
                    for (Map.Entry<String, String> entry : m.entries()) {
                        out.writeStatement(new Statement(oldInstance, " put " , new Object[] { entry.getKey(), entry.getValue() }));
                    }
         
                }
            }
         
            static public class SomeBean {
                private HashMultimap<String, String> stateMap;
         
                public HashMultimap<String, String> getStateMap() {
                    return stateMap;
                }
         
                public void setStateMap(HashMultimap<String, String> stateMap) {
                    this.stateMap = stateMap;
                }
            }
        }
        ---------- END SOURCE ----------

        CUSTOMER SUBMITTED WORKAROUND :
        Use JRE 7 u3 or lower. The bug is present in JRE 7 u4 and up.

          Attachments

            Issue Links

              Activity

                People

                • Assignee:
                  malenkov Sergey Malenkov (Inactive)
                  Reporter:
                  webbuggrp Webbug Group
                • Votes:
                  0 Vote for this issue
                  Watchers:
                  4 Start watching this issue

                  Dates

                  • Created:
                    Updated:
                    Resolved: