Avi-Levi / kryo

Automatically exported from code.google.com/p/kryo
BSD 3-Clause "New" or "Revised" License
0 stars 0 forks source link

Accessing non-public fields with bytecode #25

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
This is not an issue but rather a proposal.

You write that you use generated bytecode to access public fields and cached 
reflection to access protected and private fields.

I propose that you use bytecode corresponding to the example below to also 
access protected fields (and with a variant also package visible fields) but 
improved speed.

// an existing class with a non-private field x:
class Existing {
    protected byte x;
}

// a serializer which *can* access x within java rules:
class Serializer extends Existing {
    public static void writeObject(final ByteBuffer b, final Existing t) {
        b.put(t.x);
    }
}

The idea is to create a class which inherits from the class in question (which 
allows to access the field) but not to use instances of that class (we have no 
use for it anyway).

Accessing package visible fields is also possible with a variant of this method 
- provided the package is not protected by the SecurityManager. Just generate a 
class in that package. 

Looking at your code I think that a fairly straitforward variant or your 
MethodAccess code should do it. 

Accessing private fields is of course no possible with this approach as that 
would require geenrating access code *in* the class at question which is not 
possible *after* that class is loaded.

In the long run you might consider providing a ClassLoader which intercepts 
class load calls and adds special custom serialization methods in all classes 
of your choice. Then you'd only need to call those methods during serialization.

Yours

Gunnar Zarncke

Original issue reported on code.google.com by g.zarn...@googlemail.com on 2 Sep 2010 at 2:55

GoogleCodeExporter commented 9 years ago
This seems like a good improvement. I will get to it eventually, thanks!

Original comment by nathan.s...@gmail.com on 10 Oct 2010 at 2:49

GoogleCodeExporter commented 9 years ago

Original comment by nathan.s...@gmail.com on 10 Oct 2010 at 2:50

GoogleCodeExporter commented 9 years ago
For your idea to work, the class which accesses protected or default access 
members must be defined by the same classloader as the class it is accessing. 
Spec excerpt: 

5.3 Creation and Loading
...
At run time, a class or interface is determined not by its name alone, but by a 
pair: its fully qualified name and its defining class loader. Each such class 
or interface belongs to a single runtime package. The runtime package of a 
class or interface is determined by the package name and defining class loader 
of the class or interface.
5.4.4 Access Control
...
A field or method R is accessible to a class or interface D if and only if any 
of the following conditions is true:
* ...
* R is either protected or package private (that is, neither public nor 
protected nor private), and is declared by a class in the same runtime package 
as D.

I implemented a workaround in ReflectASM:
http://code.google.com/p/reflectasm/source/detail?r=14

I attempt reflection and setAccessible to call the protected defineClass in the 
correct classloader. If this fails, ReflectASM's classloader is used. If it 
succeeds, then protected and default access methods and fields are accessible.

Original comment by nathan.s...@gmail.com on 9 Feb 2011 at 8:48