557

I have a poorly designed class in a 3rd-party JAR and I need to access one of its private fields. For example, why should I need to choose private field is it necessary?

class IWasDesignedPoorly {
    private Hashtable stuffIWant;
}

IWasDesignedPoorly obj = ...;

How can I use reflection to get the value of stuffIWant?

Steve Chambers
  • 37,270
  • 24
  • 156
  • 208
Frank Krueger
  • 69,552
  • 46
  • 163
  • 208

14 Answers14

746

In order to access private fields, you need to get them from the class's declared fields and then make them accessible:

Field f = obj.getClass().getDeclaredField("stuffIWant"); //NoSuchFieldException
f.setAccessible(true);
Hashtable iWantThis = (Hashtable) f.get(obj); //IllegalAccessException

EDIT: as has been commented by aperkins, both accessing the field, setting it as accessible and retrieving the value can throw Exceptions, although the only checked exceptions you need to be mindful of are commented above.

The NoSuchFieldException would be thrown if you asked for a field by a name which did not correspond to a declared field.

obj.getClass().getDeclaredField("misspelled"); //will throw NoSuchFieldException

The IllegalAccessException would be thrown if the field was not accessible (for example, if it is private and has not been made accessible via missing out the f.setAccessible(true) line.

The RuntimeExceptions which may be thrown are either SecurityExceptions (if the JVM's SecurityManager will not allow you to change a field's accessibility), or IllegalArgumentExceptions, if you try and access the field on an object not of the field's class's type:

f.get("BOB"); //will throw IllegalArgumentException, as String is of the wrong type
wesley
  • 405
  • 4
  • 15
oxbow_lakes
  • 133,303
  • 56
  • 317
  • 449
  • Also note you will have to catch an exception or two off of f.get – aperkins Jul 28 '09 at 19:36
  • 4
    can you please explain the exception comments? the code will run but will throw exceptions? or the code may throw exceptions? – Nir Levy Jul 28 '09 at 20:34
  • 1
    @Nir - No - in all likelihood the code will run just fine (as the default SecurityManager will allow fields' accesibility to be changed) - but you have to *handle* checked exceptions (either catch them or declare them to be *rethrown*). I've modified my answer a little. It might be good for you to write a small test case to play around and see what happens – oxbow_lakes Jul 28 '09 at 20:42
  • @Nir - exactly what oxbow said. The code will have checked exceptions around getting the declared field, and getting the value off of the object. You just need to make sure to handle those cases. – aperkins Jul 28 '09 at 21:45
  • very helpful answer. I accidently sent in Class> static object instead of the instance. Worked well for static fields but had me confused about the rest :-) – Karl Kildén Oct 02 '12 at 18:50
  • `a.setAccessible(true); String var = a.getName(); a.get(var)` gives me `Can not set final to java.lang.String` – Ava Dec 08 '14 at 19:23
  • 3
    Sorry, this is answer is confusing to me. Perhaps show an example of typical exception handling. It's seems like the exceptions would occur when the classes are wired together incorrectly. The code sample makes it seem like the exceptions would be thrown at the corresponding llnes. – LaFayette Feb 29 '16 at 08:33
  • 2
    `getDeclaredField()` doesn't find fields if they are defined in parent classes -- you have to also iterate up through the parent class hierarchy, calling `getDeclaredField()` on each, until you find a match (after which you can call `setAccessible(true)`), or you reach `Object`. – Luke Hutchison Feb 13 '17 at 08:47
  • 1
    @oxbow_lakes doesn't it violate the original semantics of private variable. Then what the purpose of private if we still can change it through reflection. – legend Sep 16 '18 at 15:27
  • 2
    @legend you can install a security manager to forbid such access. Since Java 9, such access is not supposed to work across module borders (unless a module is open explicitly), though there’s a transitional phase regarding enforcement of the new rules. Besides that, requiring additional effort like Reflection always made a difference to non-`private` fields. It precludes accidental access. – Holger Sep 25 '18 at 08:30
  • 1
    With JDK 9+ / JPMS, if the non-public field is in a different module (`x`) from module of the class running the reflection code (`y`), then `x` must open (`opens`) itself to `y` for `f.setAccessible(true)` to succeed. – Luke Hutchison Oct 21 '18 at 01:46
  • Sorry by why this is voted as an answer, the answer below is the most efficient and easy answer there here, use FieldUtils! – Brain Bytes May 26 '19 at 23:31
  • This was listing methods instead of fields when I tried to do it on a bean injected by the SpringContext and declared as an interface. This other answer worked instead: https://stackoverflow.com/a/46890521/9768291 – payne Dec 10 '20 at 20:11
206

Try FieldUtils from Apache commons-lang3:

FieldUtils.readField(object, fieldName, true);

P.S. In my opinion, reflection is evil.

yegor256
  • 102,010
  • 123
  • 446
  • 597
  • 104
    I'm convinced you could solve most of the world's problems by stringing together a few methods from commons-lang3. – Cameron Aug 05 '15 at 18:46
  • @yegor why java allow this? mean why java allowing to access private members? – Asif Mushtaq Apr 24 '16 at 10:52
  • 1
    @yegor256 I can still access C# and C++ private members too..!! Then? all languages creators are weak? – Asif Mushtaq Apr 28 '16 at 15:04
  • 5
    @UnKnown java does not. There are two different things - java language and java as java virtual machine. The latter operates on bytecode. And there are libraries to manipulate that. So java language does not allow you to use private fields outside of the scope or does not allow to mutate final references. But it's possible to do that using the tool. Which just happens to be inside the standard library. – evgenii Aug 07 '16 at 10:22
  • @EvgeniiMorozov again question leaved with why. Why java allowed to use or created that tools? – Asif Mushtaq Aug 07 '16 at 10:25
  • @UnKnown because the vast majority of Java community have no idea what good programming practices are. They are just converted C/C++ coders who happen to be paid for building software. "Whatever works" is their philosophy. That's why Java allows this access. – yegor256 Aug 07 '16 at 17:10
  • @yegor256 you mean we can't access C# private fields? http://stackoverflow.com/questions/95910/find-a-private-field-with-reflection and I don't think so even a stupid programmer will write the code to access private fields(without any reason). – Asif Mushtaq Aug 07 '16 at 17:21
  • @UnKnown, why don't you ask why there are disassemblers, which allow to hack any piece of any software? Java doesn't really allow anything. It's just not possible to stop people doing so. If Sun wouldn't have written such a library to operate on a bytecode, someone else would. It's just a matter of time, a bit of curiosity, a bit of intelligence - most of those stuff which mean being a true hacker (in kinda old fashion so to say). – evgenii Aug 07 '16 at 22:57
  • @yegor256, I'm pretty sure you know there are few definitions of "being a hacker". Having very peculiar tools is completely orthogonal to the good design, which by the way is subjective and depends upon... – evgenii Aug 07 '16 at 23:35
  • @evgenii I'm not talking about the out-source tools. Why does java create reflection api to access the private members? I'm not understanding why are you not trying to proving that all language creators are weak instead of providing the real answer. ( Again and again I'm not talking about the out sourcing tools ) – Asif Mushtaq Aug 30 '16 at 15:00
  • @UnKnown, they're all people, we (people) do mistakes, but I just very doubt that's the reason why they created reflection in java. That's probably a good question for James Gosling. – evgenii Aug 31 '16 at 09:36
  • 4
    @UnKnown one of the reasons is that Java does not have "friend" access to enable access to the field only by an infrastructure framework like DI, ORM or XML/JSON serializer. Such frameworks need access to object fields to correctly serialize or initialize internal state of an object, but you still may need proper compile-time encapsulation enforcement for your business logic. – Ivan Gammel Dec 21 '16 at 16:51
  • You can forbid reflection by Java security policies. – vdshb Jan 25 '17 at 11:39
28

Reflection isn't the only way to resolve your issue (which is to access the private functionality/behaviour of a class/component)

An alternative solution is to extract the class from the .jar, decompile it using (say) Jode or Jad, change the field (or add an accessor), and recompile it against the original .jar. Then put the new .class ahead of the .jar in the classpath, or reinsert it in the .jar. (the jar utility allows you to extract and reinsert to an existing .jar)

As noted below, this resolves the wider issue of accessing/changing private state rather than simply accessing/changing a field.

This requires the .jar not to be signed, of course.

Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
  • 44
    This way will be pretty painful for just a simple field. – Valentin Rocher Jul 29 '09 at 08:30
  • 2
    I disagree. It allows you to not only access your field, but also to change the class if necessary if accessing the field turns out not to be sufficient. – Brian Agnew Jul 29 '09 at 08:33
  • 5
    Then you have to do that again. What happens if the jar gets an update and you use reflection for a field that no longer exists? It's exactly the same issue. You just have to manage it. – Brian Agnew Nov 23 '12 at 08:17
  • 4
    I'm astonished as to how much this gets downvoted given a) it's highlighted as a practical alternative b) it caters for scenarios in which changing a field's visibility isn't sufficient – Brian Agnew Dec 27 '12 at 09:16
  • @BrianAgnew although you're right the exact question was "How do I read a private field in Java?" and your answer is "how remove private from a field in an existing jar" I guess it's why you got downrated. – Remi Morin Aug 30 '13 at 15:48
  • 1
    "the jar utility allows you to extract and reinsert to an existing .jar" or, even more easily, just open the jar with 7-Zip, or rename the `.jar` to `.zip` and open with Windows Explorer. – wchargin Nov 09 '13 at 15:42
  • @RemiMorin - "change the field (or add an accessor)" looks about right to me – Brian Agnew Feb 20 '14 at 16:49
  • 2
    @BrianAgnew maybe it's just semantic but if we stick to the question (using reflection to read a private field) not using reflection is right away a self contradiction. But I agree you provide access to the field... but still the field is not private anymore so again we don't stick to the "read a private field" of the question. From an other angle, the .jar modification may not work in some case (signed jar), need to be done every time the jar is updated, require careful manipulation of the classpath (which you may not fully control if you are executed in an application container) etc. – Remi Morin Feb 24 '14 at 20:58
  • 1
    I think it could be hilighted you cannot *read* a value of `stuffIWant` this way, so this does not answer the question asked. – eis Sep 09 '15 at 08:11
  • +1 for the alternative. I've done this more times than I can count. Though you may not always have to re-insert it back into the jar. Most times I just stick the modified class into another package in my own project and keep the jar as a dependency so that the class can compile (if it has any dependencies from that jar -- they usually do though). If your IDE has it's own decompiler, then this process should take all of a few seconds to perform. – Cypher Aug 27 '16 at 16:13
18

One other option that hasn't been mentioned yet: use Groovy. Groovy allows you to access private instance variables as a side effect of the design of the language. Whether or not you have a getter for the field, you can just use

def obj = new IWasDesignedPoorly()
def hashTable = obj.getStuffIWant()
Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
lucas
  • 6,951
  • 4
  • 33
  • 34
  • 9
    The OP specifically asked for Java – Jochen Aug 06 '15 at 09:58
  • 3
    Many Java projects today incorporate groovy. It's enough that the project uses Spring's groovy DSL and they'll have groovy on the classpath for example. In which case this answer is useful, and while not directly answering the OP, it will be of benefit for many visitors. – Amir Abiri Jan 23 '16 at 19:59
13

Using the Reflection in Java you can access all the private/public fields and methods of one class to another .But as per the Oracle documentation in the section drawbacks they recommended that :

"Since reflection allows code to perform operations that would be illegal in non-reflective code, such as accessing private fields and methods, the use of reflection can result in unexpected side-effects, which may render code dysfunctional and may destroy portability. Reflective code breaks abstractions and therefore may change behavior with upgrades of the platform"

here is following code snapts to demonstrate basic concepts of Reflection

Reflection1.java

public class Reflection1{

    private int i = 10;

    public void methoda()
    {

        System.out.println("method1");
    }
    public void methodb()
    {

        System.out.println("method2");
    }
    public void methodc()
    {

        System.out.println("method3");
    }

}

Reflection2.java

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;


public class Reflection2{

    public static void main(String ar[]) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
    {
        Method[] mthd = Reflection1.class.getMethods(); // for axis the methods 

        Field[] fld = Reflection1.class.getDeclaredFields();  // for axis the fields  

        // Loop for get all the methods in class
        for(Method mthd1:mthd)
        {

            System.out.println("method :"+mthd1.getName());
            System.out.println("parametes :"+mthd1.getReturnType());
        }

        // Loop for get all the Field in class
        for(Field fld1:fld)
        {
            fld1.setAccessible(true);
            System.out.println("field :"+fld1.getName());
            System.out.println("type :"+fld1.getType());
            System.out.println("value :"+fld1.getInt(new Reflaction1()));
        }
    }

}

Hope it will help.

Simmant
  • 1,477
  • 25
  • 39
6

Java 9 introduced Variable Handles. You can access a private field of a class using them.

The code for your example will look like following:

var lookup = MethodHandles.lookup();
var handle = MethodHandles
    .privateLookupIn(IWasDesignedPoorly.class, lookup)
    .findVarHandle(IWasDesignedPoorly.class, "stuffIWant", Hashtable.class);
var value = handle.get(obj);

It is also advisable to use Lookup and VarHandle objects as static final fields.

Nolequen
  • 3,032
  • 6
  • 36
  • 55
5

As oxbow_lakes mentions, you can use reflection to get around the access restrictions (assuming your SecurityManager will let you).

That said, if this class is so badly designed that it makes you resort to such hackery, maybe you should look for an alternative. Sure this little hack might be saving you a few hours now, but how much will it cost you down the road?

Laurence Gonsalves
  • 137,896
  • 35
  • 246
  • 299
  • 3
    I'm luckier than that actually, I'm just using this code to extract some data, after that I can toss it back into the Recycle Bin. – Frank Krueger Jul 28 '09 at 19:43
  • 2
    Well in that case, hack away. :-) – Laurence Gonsalves Jul 28 '09 at 19:50
  • 3
    This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post. – Mureinik Dec 20 '14 at 20:04
  • @Mureinik - It does answer the question, with the words "you can use reflection". It lacks an example or any greater explanation or how, but it is an answer. Downvote it if you don't like it. – ArtOfWarfare Jan 19 '17 at 03:46
4

Use the Soot Java Optimization framework to directly modify the bytecode. http://www.sable.mcgill.ca/soot/

Soot is completely written in Java and works with new Java versions.

pcpratts
  • 388
  • 3
  • 6
4

If using Spring:

In a testing context, ReflectionTestUtils provides some handy tools that can help out here with minimal effort. It's described as being "for use in unit and integration testing scenarios".

In a non-testing context, there is also a similar class named ReflectionUtils but this is described as "Only intended for internal use" - see this answer for a good interpretation of what this means.

To address the example in the original post:

Hashtable iWantThis = (Hashtable)ReflectionTestUtils.getField(obj, "stuffIWant");
Steve Chambers
  • 37,270
  • 24
  • 156
  • 208
  • 1
    If you decide to use a Utils class by Spring, you really should use the non-test one (https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/util/ReflectionUtils.html#handleReflectionException-java.lang.Exception) instead unless, of course, you're actually using it for unit tests. – Sync Nov 08 '17 at 10:57
3

You need to do the following:

private static Field getField(Class<?> cls, String fieldName) {
    for (Class<?> c = cls; c != null; c = c.getSuperclass()) {
        try {
            final Field field = c.getDeclaredField(fieldName);
            field.setAccessible(true);
            return field;
        } catch (final NoSuchFieldException e) {
            // Try parent
        } catch (Exception e) {
            throw new IllegalArgumentException(
                    "Cannot access field " + cls.getName() + "." + fieldName, e);
        }
    }
    throw new IllegalArgumentException(
            "Cannot find field " + cls.getName() + "." + fieldName);
}
Luke Hutchison
  • 8,186
  • 2
  • 45
  • 40
2

You can use jOOR for that.

class Foo {
    private final String value = "ABC";
}
class Bar {
    private final Foo foo = new Foo();
    public String value() {
        return org.joor.Reflect
            .on(this.foo)
            .field("value")
            .get();
    }
}
class BarTest {
    @Test
    void accessPrivateField() {
        Assertions.assertEquals(new Bar().value(), "ABC");
    }
}
andreoss
  • 1,570
  • 1
  • 10
  • 25
1

Just an additional note about reflection: I have observed in some special cases, when several classes with the same name exist in different packages, that reflection as used in the top answer may fail to pick the correct class from the object. So if you know what is the package.class of the object, then it's better to access its private field values as follows:

org.deeplearning4j.nn.layers.BaseOutputLayer ll = (org.deeplearning4j.nn.layers.BaseOutputLayer) model.getLayer(0);
Field f = Class.forName("org.deeplearning4j.nn.layers.BaseOutputLayer").getDeclaredField("solver");
f.setAccessible(true);
Solver s = (Solver) f.get(ll);

(This is the example class that was not working for me)

xtof54
  • 1,233
  • 11
  • 15
1

It is quite easy with the tool XrayInterface. Just define the missing getters/setters, e.g.

interface BetterDesigned {
  Hashtable getStuffIWant(); //is mapped by convention to stuffIWant
}

and xray your poor designed project:

IWasDesignedPoorly obj = new IWasDesignedPoorly();
BetterDesigned better = ...;
System.out.println(better.getStuffIWant());

Internally this relies on reflection.

CoronA
  • 7,717
  • 2
  • 26
  • 53
-2

Try to go around the problem for the case, the calass of which you want to set/get data is one of your own classes.

Just create a public setter(Field f, Object value) and public Object getter(Field f) for that. You can even do some securoty check on your own inside theses member functions. E.g. for the setter:

class myClassName {
    private String aString;

    public set(Field field, Object value) {
        // (A) do some checkings here  for security

        // (B) set the value
        field.set(this, value);
    }
}

Of course, now you have to find out the java.lang.reflect.Field for sString prior to setting of field value.

I do use this technique in a generic ResultSet-to-and-from-model-mapper.

karldegen
  • 113
  • 8