UcasRichard / snakeyaml

Automatically exported from code.google.com/p/snakeyaml
Apache License 2.0
0 stars 0 forks source link

Unable to dump JavaBean that inherits from a protected base class #50

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
The following Java program will reproduce the problem:

package sf.snakeyaml_test;

import org.yaml.snakeyaml.Yaml;

public class SnakeyamlTest
{

  public static interface SomeBean
  {

    String getAttribute1();

    String getAttribute2();
  }

  /*public */static abstract class BaseSomeBean
      implements SomeBean
  {

    private String attribute1;

    public final String getAttribute1()
    {
      return attribute1;
    }

    public final void setAttribute1(String attribute1)
    {
      this.attribute1 = attribute1;
    }

  }

  public static final class SomeBeanImpl
      extends BaseSomeBean
  {

    private String attribute2;

    public SomeBeanImpl(final String attribute1, final String attribute2)
    {
      setAttribute1(attribute1);
      setAttribute2(attribute2);
    }

    public String getAttribute2()
    {
      return attribute2;
    }

    public void setAttribute2(String attribute2)
    {
      this.attribute2 = attribute2;
    }

  }

  public static void main(String[] args)
  {
    final SomeBean someBean = new SomeBeanImpl("value1", "value2");
    final Yaml dumper = new Yaml();
    // final JavaBeanDumper dumper = new JavaBeanDumper();
    final String output = dumper.dump(someBean);
    System.out.println(output);
  }

}

What is the expected output? What do you see instead?
Expected output:
!!sf.snakeyaml_test.SnakeyamlTest$SomeBeanImpl {attribute1: value1,
attribute2: value2}

What I get instead:
Exception in thread "main" org.yaml.snakeyaml.error.YAMLException: Unable
to find getter for property 'attribute1' on object
sf.snakeyaml_test.SnakeyamlTest$SomeBeanImpl@c1b531:java.lang.IllegalAccessExcep
tion:
Class org.yaml.snakeyaml.introspector.MethodProperty can not access a
member of class sf.snakeyaml_test.SnakeyamlTest$BaseSomeBean with modifiers
"public final"
    at org.yaml.snakeyaml.introspector.MethodProperty.get(MethodProperty.java:62)
    at
org.yaml.snakeyaml.representer.Representer.representJavaBean(Representer.java:97
)
    at
org.yaml.snakeyaml.representer.Representer$RepresentJavaBean.representData(Repre
senter.java:67)
    at
org.yaml.snakeyaml.representer.BaseRepresenter.representData(BaseRepresenter.jav
a:107)
    at
org.yaml.snakeyaml.representer.BaseRepresenter.represent(BaseRepresenter.java:60
)
    at org.yaml.snakeyaml.Dumper.dump(Dumper.java:51)
    at org.yaml.snakeyaml.Yaml.dumpAll(Yaml.java:140)
    at org.yaml.snakeyaml.Yaml.dumpAll(Yaml.java:113)
    at org.yaml.snakeyaml.Yaml.dump(Yaml.java:101)
    at sf.snakeyaml_test.SnakeyamlTest.main(SnakeyamlTest.java:63)

What version of the product are you using? On what operating system?
snakeyaml 1.5 on Windows XP SP3, with Sun JDK 1.5.0_14

Original issue reported on code.google.com by sualeh.f...@gmail.com on 12 Feb 2010 at 4:04

GoogleCodeExporter commented 9 years ago
I did not quite catch you.
Just uncomment the public modifier for BaseSomeBean to make it work.

SnakeYAML resides in another package then your code. That is why to be 'public' 
is 
important.

The fact that 'main' method is in the same package does give SnakeYAML parser 
more privileges.

Original comment by py4fun@gmail.com on 12 Feb 2010 at 5:43

GoogleCodeExporter commented 9 years ago
Do you mean the error message is confusing ?

Original comment by py4fun@gmail.com on 12 Feb 2010 at 5:47

GoogleCodeExporter commented 9 years ago

Original comment by aso...@gmail.com on 16 Feb 2010 at 6:52

GoogleCodeExporter commented 9 years ago
The point is: there should be no exception at all - Snakeyaml should just be 
able to
obtain the value of the "attribute1" property. Please take a look at any other 
Java
serialization package, and see how they do this - I would suggest looking at 
XStream
or Commons BeanUtils, which can successfully serialize this code.

Here is the alternate code using Commons BeanUtils, that you can try out:

  public static void main(String[] args)
  {
    final SomeBean someBean = new SomeBeanImpl("value1", "value2");
    final BeanMap beanMap = new BeanMap(someBean);
    System.out.println(beanMap.values());
  }

Original comment by sualeh.f...@gmail.com on 17 Feb 2010 at 12:59

GoogleCodeExporter commented 9 years ago

Original comment by aso...@gmail.com on 17 Feb 2010 at 4:47

GoogleCodeExporter commented 9 years ago
When I execute your example with BeanMap I get exactly the same error.
It does not throw an exception but it still cannot access the attribute:

WARN: Exception: java.lang.IllegalAccessException: Class
org.apache.commons.collections.BeanMap can not access a member of class
org.yaml.snakeyaml.issues.issue50.SnakeyamlTest$BaseSomeBean with modifiers 
"public
final"
java.lang.IllegalAccessException: Class org.apache.commons.collections.BeanMap 
can
not access a member of class
org.yaml.snakeyaml.issues.issue50.SnakeyamlTest$BaseSomeBean with modifiers 
"public
final"
    at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:95)
    at java.lang.reflect.Method.invoke(Method.java:607)
    at org.apache.commons.collections.BeanMap.get(BeanMap.java:333)
    at org.apache.commons.collections.BeanMap$10.next(BeanMap.java:485)
    at org.apache.commons.collections.BeanMap.values(BeanMap.java:441)
    at org.yaml.snakeyaml.issues.issue50.SnakeyamlTest.test2(SnakeyamlTest.java:78)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:616)
    at junit.framework.TestCase.runTest(TestCase.java:164)
    at junit.framework.TestCase.runBare(TestCase.java:130)
    at junit.framework.TestResult$1.protect(TestResult.java:106)
    at junit.framework.TestResult.runProtected(TestResult.java:124)
    at junit.framework.TestResult.run(TestResult.java:109)
    at junit.framework.TestCase.run(TestCase.java:120)
    at
org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestR
eference.java:130)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner
.java:467)
    at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner
.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.jav
a:197)
[class org.yaml.snakeyaml.issues.issue50.SnakeyamlTest$SomeBeanImpl, null, 
value2]

Original comment by aso...@gmail.com on 17 Feb 2010 at 8:08

Attachments:

GoogleCodeExporter commented 9 years ago
I was mistaken about BeanUtils. Please could you also test with XStream, with 
this 
code:

pom.xml
    <dependency>
      <groupId>com.thoughtworks.xstream</groupId>
      <artifactId>xstream</artifactId>
      <version>1.3.1</version>
    </dependency>

SnakeyamlTest.java
    public void test3() throws IOException {
        final StringWriter writer = new StringWriter();
        final XStream xstream = new XStream();
        xstream.toXML(someBean, writer);
        System.out.println(writer);
    }

Original comment by sualeh.f...@gmail.com on 20 Feb 2010 at 6:21

GoogleCodeExporter commented 9 years ago
http://joe.truemesh.com/blog//000479.html

Original comment by sualeh.f...@gmail.com on 24 Feb 2010 at 8:10

GoogleCodeExporter commented 9 years ago
It looks like a problem in Eclipse.

This test fails in Eclipse but works if you run it with Maven:

http://code.google.com/p/snakeyaml/source/browse/src/test/java/org/yaml/snakeyam
l/issues/issue50/SnakeyamlTest.java

Try: mvn clean test

Original comment by aso...@gmail.com on 1 Mar 2010 at 2:25

GoogleCodeExporter commented 9 years ago
It looks like it is JDK (or compiler ?) specific.

Fails with:
- Eclipse compiler
- OpenJDK 1.6, Ubuntu
- Sun JDK 1.5, Ubuntu

Works with:
- Sun JDK 1.6, Windows
- Sun JDK 1.6, Ubuntu

Any information is mush appreciated.

Original comment by aso...@gmail.com on 1 Mar 2010 at 6:03

GoogleCodeExporter commented 9 years ago
XStream works with the Eclipse compiler, for me. It seems that there is some 
version 
specific functionality in XStream - http://xstream.codehaus.org/faq.html

Basically, I wanted to ask if you could consider using XStream as the engine 
for 
your serialization. XStream already has two JSON "hierarchical stream drivers", 
and 
it would be great to have a YAML hierarchical stream driver as well.

Original comment by sualeh.f...@gmail.com on 2 Mar 2010 at 12:53

GoogleCodeExporter commented 9 years ago
Using XStream as the engine for the serialization is a major change for 
SnakeYAML.
Since this is the only reported issue and it is _very_ specific I do not think 
it is
worth to implement.

The other way around - implementing YAML "hierarchical stream driver" for 
XStream may
be useful for those who use YAML only in Java. XStream is very Java-centric. It
assumes that you can always change the Java class to achieve the result. But 
the YAML
document may be generated or expected to be consumed in another language. 
XStream use
annotations, 'transient' modifier, explicit Java class names etc.

Original comment by aso...@gmail.com on 2 Mar 2010 at 12:10

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
Another approach - would this help?
java.lang.reflect.AccessibleObject.setAccessible(boolean)

Original comment by sualeh.f...@gmail.com on 2 Mar 2010 at 1:31

GoogleCodeExporter commented 9 years ago
Thank you very much !!!
It is fixed. Check the latest source.
I have tested the fix with different JDKs. It works.

It will be released in version 1.7

Original comment by aso...@gmail.com on 2 Mar 2010 at 3:27