References to a private field using Guava Reflection - java

I would like to clarify something.
With "plain" Java reflection techniques (without using a library) afaik it is not possible to get a reference to a private field (I mean the java.lang.reflect.Field object, no the field value).
For example, if I have this class:
public class MyClass {
private String field1;
}
If I attempt to execute this:
Field field = MyClass.class.getField("field1");
I will get a NoSuchFieldException exception, as expected.
With the Guava Reflection library, if I try to execute this:
Object o = new MyClass();
Property property = Properties.getPropertyByName(o, "field1");
Field f = property.getField();
I get the following exception:
java.lang.IllegalStateException: Unknown property: field1 in class MyClass
And this was also expected. However, if I add a getter method, like this:
public class MyClass {
private String field1;
public String getField1() {return field1;}
}
Then the Guava-reflection code is working.
I have to confess I am a bit loss about this. I understand that a reflection library could use a getter to return the value of a private instance variable, but the Field object itself just because a getter exists ?. Does someone has an idea how does this happen ?

You can reflect on private fields using standard java reflection, which is probably what Guava is doing under the hood:
Class<?> c = ... some class ...
Field field = c.getDeclaredField("name");
field.setAccessible(true);
Object value = field.get(object);
getDeclaredField allows you to obtain private fields.
setAccessible is needed to prevent security issues.
Anyway, as a best practice, consider using reflection on public members only, so work with getters/setters if possible.
Hope that helps.

Field extends AccesibleObject, which has a method setAccessible(), allowing you to get access to the value of a private field.
Guava-Reflection (note that this library is distinct from Guava) is making your private fields accessible in methods like Property.getFieldValue()

Related

Casting a String to another type as a parameter of a method in Java reflection

I am trying to pass a value to a method by means of reflection in Java.
Namely, say we have string
String value = (some string representation of a value of type Type);
Say, we have a class with no-args-contructor, a single field int field and a single method, a setter method setTheField:
public class SomeClass{
private SomeType field;
SomeClass(){};
public void setTheField(SomeType parameter){
this.field = parameter
}
}
where SomeType of field may be primitive, wrapper or LocalDate / LocalDateTime.
If I take the setter (say):
Method setter = SomeClass.getClass().getDeclaredMethods()[0];
and then find out its parameters (say):
parametersList = Arrays.stream(setter.getParameters())
.collect(Collectors.toList());
Then if check if the setter requires a single parameter:
if (parametersList.size() != 1) {
throw new IllegalArgumentException("Setter named = " +
setter.getName() +
" is not a single parameter setter!");
}
What I really want to do then, is to pass string to 'setter' on some object SomeClass object = new SomeClass(); as setter.invoke(object, value); and I need somehow to cats String value to SomeType but I can not figure out how to do it uniformly.
Though, it seems a standard situation to appear and I hope someone more enlightened then me in Java can quickly figure out what to do.
Any suggestions are welcome.
Addendum:
I elaborate some more here.
The task I am trying to do is the following. Suppose I have an annotations #Column{String name} targeted to methods (or fields). Suppose I also have some domain class SomeClass with some setters (fields) annotated as #Column. I have to read from CSV top row with column names (headers to link data to the annotation's name), then I have to return a list of objects of my domain class SomeClass. This is the reason I am using reflection and I see no other way around.
Without more context this looks like a design problem. Why go through all the work to grab a setter by reflection and given a String, get a value compatible with the setter argument's type? If there's no other way around this problem, it is not possible to just cast a String to some other type. One possibility is making a factory class.
Assumption: the setter's argument type is some class called MyType.
class ArgumentFactory {
MyType valueFor(String in) {
// based on the string's value, put the conversion logic here
if (in == null || in.isEmpty()) {
return new MyType();
}
// add other cases as necessary ...
}
}
Then you have
ArgumentFactory factory = new ArgumentFactory();
// ...
String value = "qwerty";
setter.invoke(object, argumentFactory.valueFor(value));

Access level aware dependency injection into inherited field

At work there is a process framework. It uses keys and containers to set parameters without the use of dedicated constructors (it's basically the type safe heterogeneous container pattern).
I recently added dependency injection.
Below you find a representative example (it lacks some null checks, access control, etc.)
private static void inject(Process instance, Container c) throws Exception
{
Class<?> reference = instance.getClass();
for (Field field : reference.getDeclaredFields())
{
Inject inject = field.getAnnotation(Inject.class);
Key<Object> key = new Key<>(inject.key());
field.set(instance, c.getObject(key));
}
}
The implementation is working, but now I need to enhance it in order to also inject into inherited fields.
I had no problem retrieving the type hierachy and all the annotated, inherited fields. But in order to comply with Java, I must not inject into every retrieved field.
Only when the field is:
public
protected
package-privated and declared in a class that has the same package as reference
private and declared in class that encloses reference, which has to be an inner class (non-static nested class).
Items 1 - 3 are easy to check for. I have difficulties with the last item. Is there an elegant solution?
I thougt about using java.lang.Class.isMemberClass() and comparing class names.
Currently my check looks like this
private static boolean accessAllowed(Class<?> reference, Field field)
{
int modifiers = field.getModifiers();
boolean hasAccess = Modifier.isPublic(modifiers);
hasAccess |= Modifier.isProtected(modifiers);
// TODO fix
hasAccess |= Modifier.isPrivate(modifiers) /* add check as defined in 4. */;
// no access and not private means field is package-private
if (!hasAccess && !Modifier.isPrivate(modifiers))
hasAccess = reference.getPackage().equals(field.getDeclaringClass().getPackage());
return hasAccess;
}
Is there an easy and/or efficient way to find out whether a class is enclosed by another class? Or is there another way to find out whether I am allowed to inject?
The following solution should handle the private case.
The derived class is reference, it tries to set members inherited from fieldDeclaringClass
static boolean hasPrivateAccessRelation(Class<?> reference, Class<?> fieldDeclaringClass)
{
boolean isMemberClass = reference.isMemberClass();
boolean isEnclosingClass = reference.getName().contains(fieldDeclaringClass.getName());
// static nested classes can't access private members of enclosing class
return isMemberClass && isEnclosingClass && !Modifier.isStatic(reference.getModifiers());
}
The code works if the derived class is a inner class of fieldDeclaringClass. It fails if it is a static nested classes, since these have no access to private fields of enclosing classes.
A previous check is necessary to make sure reference and fieldDeclaringClass are not equal. Because in that case static would be a valid modifier, since a nested class always has access to its own fields.

Is it possible to do a final class immutable in Java?

Recently on the interview I had an interesting question.
We have mutable class:
final class Example {
private int i;
private String s;
private Object o;
// get, set
}
And instance of this class Example e = new Example();
Can we somehow make this instance immutable? Without changing original class.
My thoughts:
Deep cloning of this instance? But not sure if it's possible.
Maybe something like serialization/deserialization?
If you are unable to make modifications to the Example class and you cannot subclass it (in your snippet, it is marked as final) the closest solution I can think of is to create a wrapper class, which is immutable. This is not a perfect solution, and has it's drawbacks.
First, how to do it:
final class ImmutableExample {
// Redeclare every field as in the Example class
// but make sure they can't be reassigned
// (in this case I'll declare them as final)
private final int i;
private final String s;
private final Object o;
ImmutableExample(Example mutableExample) {
// copy fields from original
this.i = mutableExample.getI();
this.s = mutableExample.getS();
this.o = mutableExample.getO();
}
// add getters but definitely no setters
}
Then everywhere you have code like this:
Example e = new Example();
e.setI(42); // etc
Change to:
Example e = new Example();
e.setI(42); // etc
ImmutableExample immutableE = new ImmutableExample(e);
And pass around references to immutableE, and make sure that the e reference does not escape.
Now, for the drawbacks:
ImmutableExample is not an instance of Example, so you cannot pass the immutable type to a method which expects the mutable type, and operations like if (immutableE instanceof Example) or (Example)immutableE will not work as before
You have to be very careful that every field of Example is also immutable, or ImmutableExample will also be mutable. Consider, for example, that the field of type Object could be something mutable, like a HashMap or a Date.
When the Example class changes, you have to repeat the change in ImmutableExample.
If it was possible to subclass Example, or if it was an interface, this approach might be more useful, but I can't see any other way when Example cannot be subclassed.
If each of those fields have getters/setters, then to make it immutable, you will have to
Make each field private and final
Make a copy of each field when it's getter is called
Remove all setters
Any methods within the class that changes it's state must either be removed or use the new getters to access any internals
Immutability is a property of a class not an instance. So besides bytecode twiddling or other means to change the class; not possible.
With a none final class i would create an immutable decorator. That would not make the instance immutable, but provide an immutable wrapper to that instance.
You could not assign the instance to any variable/field, making it impossible to change it ;)

How to create an instance of enum using reflection in Java?

When I'm reading Effective Java, the author told me that a single-element enum type is the best way to implement a singleton, because we don't have to consider sophisticated serialization or reflection attacks. This means we cannot create an instance of enum using reflection, right?
I have done some tests, with an enum class here:
public enum Weekday {}
Then I tried to create an instance of Weekday:
Class<Weekday> weekdayClass = Weekday.class;
Constructor<Weekday> cw = weekdayClass.getConstructor(null);
cw.setAccessible(true);
cw.newInstance(null);
As you know, it doesn't work. When I change the key word enum to class, it works. I want to know why. Thank you.
This is built into the language. From the Java Language Specification (§8.9):
It is a compile-time error to attempt to explicitly instantiate an enum type (§15.9.1). The final clone method in Enum ensures that enum constants can never be cloned, and the special treatment by the serialization mechanism ensures that duplicate instances are never created as a result of deserialization. Reflective instantiation of enum types is prohibited. Together, these four things ensure that no instances of an enum type exist beyond those defined by the enum constants.
The whole purpose of this is to allow the safe use of == to compare Enum instances.
EDIT: See the answer by #GotoFinal for how to break this "guarantee" using reflection.
It is possible to create new enum instance in runtime - but it is very bad idea and might break in any update. You can use unsafe or reflections for this.
Like at this example enum:
public enum Monster {
ZOMBIE(Zombie.class, "zombie"),
ORK(Ork.class, "ork"),
WOLF(Wolf.class, "wolf");
private final Class<? extends Entity> entityClass;
private final String entityId;
Monster(Class<? extends Entity> entityClass, String entityId) {
this.entityClass = entityClass;
this.entityId = "monster:" + entityId;
}
public Class<? extends Entity> getEntityClass() { return this.entityClass; }
public String getEntityId() { return this.entityId; }
public Entity create() {
try { return entityClass.newInstance(); }
catch (InstantiationException | IllegalAccessException e) { throw new InternalError(e); }
}
}
We can use
Class<Monster> monsterClass = Monster.class;
// first we need to find our constructor, and make it accessible
Constructor<?> constructor = monsterClass.getDeclaredConstructors()[0];
constructor.setAccessible(true);
// this is this same code as in constructor.newInstance, but we just skipped all that useless enum checks ;)
Field constructorAccessorField = Constructor.class.getDeclaredField("constructorAccessor");
constructorAccessorField.setAccessible(true);
// sun.reflect.ConstructorAccessor -> internal class, we should not use it, if you need use it, it would be better to actually not import it, but use it only via reflections. (as package may change, and will in java 9+)
ConstructorAccessor ca = (ConstructorAccessor) constructorAccessorField.get(constructor);
if (ca == null) {
Method acquireConstructorAccessorMethod = Constructor.class.getDeclaredMethod("acquireConstructorAccessor");
acquireConstructorAccessorMethod.setAccessible(true);
ca = (ConstructorAccessor) acquireConstructorAccessorMethod.invoke(constructor);
}
// note that real constructor contains 2 additional parameters, name and ordinal
Monster enumValue = (Monster) ca.newInstance(new Object[]{"CAERBANNOG_RABBIT", 4, CaerbannogRabbit.class, "caerbannograbbit"});// you can call that using reflections too, reflecting reflections are best part of java ;)
On java 9 this might not compile due to usage of internal class as I described that in comment - you can skip that using unsafe or even more reflections.
But then we also need to add that constant to enum itself, so Enum.values() will return valid list, we can do this by changing value of final field using good old trick to make final field non-final again:
static void makeAccessible(Field field) throws Exception {
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~ Modifier.FINAL);
}
And then just change that field to new value that include our new field:
Field valuesField = Monster.class.getDeclaredField("$VALUES");
makeAccessible(valuesField);
// just copy old values to new array and add our new field.
Monster[] oldValues = (Monster[]) valuesField.get(null);
Monster[] newValues = new Monster[oldValues.length + 1];
System.arraycopy(oldValues, 0, newValues, 0, oldValues.length);
newValues[oldValues.length] = enumValue;
valuesField.set(null, newValues);
There is also another field that store enum constant, so it is important to do similar trick to it too:
private volatile transient T[] enumConstants = null; - in Class.class, note that it can be null - java will regenerate them on next usage.
private volatile transient Map<String, T> enumConstantDirectory = null; - in Class.class, note that it can be null too, same as field above.
So just set them to null using reflections and your new value is ready to use.
The only impossible thing without editing class using instrumentation or other tricks is to add real field to that enum for our new value.
Also it is possible to create new enum instance using Unsafe class:
public static void unsafeWay() throws Throwable {
Constructor<?> constructor = Unsafe.class.getDeclaredConstructors()[0];
constructor.setAccessible(true);
Unsafe unsafe = (Unsafe) constructor.newInstance();
Monster enumValue = (Monster) unsafe.allocateInstance(Monster.class);
}
But unsafe class does not call the constructor, so you need to init all fields manually...
Field ordinalField = Enum.class.getDeclaredField("ordinal");
makeAccessible(ordinalField);
ordinalField.setInt(enumValue, 5);
Field nameField = Enum.class.getDeclaredField("name");
makeAccessible(nameField);
nameField.set(enumValue, "LION");
Field entityClassField = Monster.class.getDeclaredField("entityClass");
makeAccessible(entityClassField);
entityClassField.set(enumValue, Lion.class);
Field entityIdField = Monster.class.getDeclaredField("entityId");
makeAccessible(entityIdField);
entityIdField.set(enumValue, "Lion");
Note that you also need to initialize internal enum fields.
Also using unsafe it should be possible to declare new class to create new instance of abstract enum classes. I used javassist library to reduce code needed to generate new class:
public class Test {
public static void main(String[] args) throws Exception {
System.out.println(MyEnum.VALUE.getSomething());
ClassPool classPool = ClassPool.getDefault();
CtClass enumCtClass = classPool.getCtClass(MyEnum.class.getName());
CtClass ctClass = classPool.makeClass("com.example.demo.MyEnum$2", enumCtClass);
CtMethod getSomethingCtMethod = new CtMethod(CtClass.intType, "getSomething", new CtClass[0], ctClass);
getSomethingCtMethod.setBody("{return 3;}");
ctClass.addMethod(getSomethingCtMethod);
Constructor<?> unsafeConstructor = Unsafe.class.getDeclaredConstructors()[0];
unsafeConstructor.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeConstructor.newInstance();
MyEnum newInstance = (MyEnum) unsafe.allocateInstance(ctClass.toClass());
Field singletonInstance = MyEnum.class.getDeclaredField("VALUE");
makeAccessible(singletonInstance);
singletonInstance.set(null, newInstance);
System.out.println(MyEnum.VALUE.getSomething());
}
static void makeAccessible(Field field) throws Exception {
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~ Modifier.FINAL);
}
}
enum MyEnum {
VALUE {
#Override
public int getSomething() {
return 5;
}
};
public abstract int getSomething();
}
This will print 5 and then 3. Note that this is impossible to enum classes that does not contain subclasses - so without any overriden methods, as then enum is declared as final class.
Source: https://blog.gotofinal.com/java/diorite/breakingjava/2017/06/24/dynamic-enum.html
This may be reviving a dead post, but you can get an instance of every constant declared using Weekday.class.getEnumConstants(). This returns an array of all the constatants, where getting a single instance is trivial, getEnumConstants()[0].
So if your objective is to persistent and then reconstructed the enum information. You will need to persist the enumClassName and its value.
public enum DaysOfWeek{ Mon, Tue, Wed, Thu, Fri, Sat, Sun }
DaysOfWeek dow = DaysOfWeek.Tue;
String value = dow.toString();
String enumClassName = dow.getClass().getName();
// Persist value and enumClassName
// ...
// Reconstitute the data
Class clz = Class.forName(enumClassName);
Object o = Enum.valueOf(clz, value);
DaysOfWeek dow2 = (DaysOfWeek)o;
System.out.println(dow2);
It is correct that new instances of an enum class cannot be created retro-actively, not even with reflection.
The following code demonstrates this:
val weekdayClass = classOf[Weekday]
val weekdayConstructor = weekdayClass getDeclaredConstructor (classOf[String], classOf[Int])
weekdayConstructor setAccessible true
weekdayConstructor newInstance ("", Integer.valueOf(0))
Usually, this should work. But in the case of enums, this is special-cased in Constructor#newInstance:
if ((clazz.getModifiers() & Modifier.ENUM) != 0)
throw new IllegalArgumentException("Cannot reflectively create enum objects");
Thus, we receive the following exception when trying to instantiate a new enum instance:
java.lang.IllegalArgumentException: Cannot reflectively create enum objects
at java.lang.reflect.Constructor.newInstance(Constructor.java:520)
...
I assume that the last approach (which will probably be successful, because no checks or constructors are run) involves sun.misc.Unsafe#allocateInstance.
Enums has been designed to be treated as constant objects. It overrides readObject and throws invalid object exception to prevent default serialization. Also it overrides clone() and throws clone not supported exception. As far as reflection is concerned, the constructor of Enum is protected.So if you use above code it will throw NoSuchMethodFound.
Even if you use getDeclaredConstructor() instead of getConstructor, you should get the same exception. I assume its been restricted through SecurityManager in java.

Getting value of public static final field/property of a class in Java via reflection

Say I have a class:
public class R {
public static final int _1st = 0x334455;
}
How can I get the value of the "_1st" via reflection?
First retrieve the field property of the class, then you can retrieve the value. If you know the type you can use one of the get methods with null (for static fields only, in fact with a static field the argument passed to the get method is ignored entirely). Otherwise you can use getType and write an appropriate switch as below:
Field f = R.class.getField("_1st");
Class<?> t = f.getType();
if(t == int.class){
System.out.println(f.getInt(null));
}else if(t == double.class){
System.out.println(f.getDouble(null));
}...
R.class.getField("_1st").get(null);
Exception handling is left as an exercise for the reader.
Basically you get the field like any other via reflection, but when you call the get method you pass in a null since there is no instance to act on.
This works for all static fields, regardless of their being final. If the field is not public, you need to call setAccessible(true) on it first, and of course the SecurityManager has to allow all of this.
I was following the same route (looking through the generated R class) and then I had this awful feeling it was probably a function in the Resources class. I was right.
Found this:
Resources::getIdentifier
Thought it might save people some time. Although they say its discouraged in the docs, which is not too surprising.
I was looking for how to get a private static field and landed here.
For fellow searchers, here is how:
public class R {
private static final int _1st = 0x334455;
}
class ReflectionHacking {
public static main(String[] args) {
Field field = R.class.getFieldDeclaration("_1st");
field.setAccessible(true);
int privateHidenInt = (Integer)field.get(null);
}
}

Categories

Resources