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.
Related
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));
When I tried to understand "Unsafe.objectFieldOffset", I am confused by the comments in the code.
// Any given field will always have the same offset, and no two distinct fields of the same class will ever have the same offset.
Does this mean that I get the offset of a field in the abstract class, this field still has the same offset in the implementation class because they are the same field?
The following is sample code, just to illustrate the problem:
public abstract class Parent {
protected Object value;
}
// Because the question is asked for any implementation class, only a simple example is given
public class Son extends Parent {
public Son(Object value) {
this.value = value;
}
Object useless_1;
Object useless_2;
Object useless_3;
Object useless_4;
}
public class ParentTool {
protected static final long offset;
private static final Unsafe unsafe;
// Initialize static fields
static {
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
unsafe = (Unsafe) field.get(null);
offset = unsafe.objectFieldOffset(Parent.class.getDeclaredField("value"));
} catch (Throwable e) {
throw new Error(e);
}
}
// Hope this method can get and set the fields correctly
protected static Object getAndSetValue(Parent parent, Object newValue) {
return unsafe.getAndSetObject(parent, offset, newValue);
}
}
The startup class used for testing is as follows
public class Program {
public static void main(String[] args) {
Son son = new Son("hello");
Object value;
value = ParentTool.getAndSetValue(son, "world");
System.out.println(value == "hello"); // true
value = ParentTool.getAndSetValue(son, "test");
System.out.println(value == "world"); // true
}
}
The operation results are as expected
true
true
Does "getAndSetValue" always work for any class that inherits Parent?
Does this depend on the specific virtual machine implementation?
The JDK version I use is shown below
OpenJDK 64-Bit Server VM Corretto-8.222.10.3
This question was raised out of curiosity about the Unsafe class. If this question is too broad or not suitable here, please let me know in the comments to improve or delete the question.
Child classes typically share the structure of a parent class, possibly adding more fields after all parent fields. This is not specific to Java - the inheritance in other languages (e.g. C++) is implemented in a similar way. This makes possible to use a child class as an instance of a parent class efficiently without a dynamic type check.
Therefore, the offset of the field will remain the same in the parent class and in its all descendant classes. The JVM is not required to do so, but all reasonable implementations I'm aware of, follow this rule.
Strictly speaking, Unsafe class is already an implementation detail of the particular JVM, so all statements about Unsafe are VM-specific by definition.
I have code which is setting values on an object using its setter methods. One of the setters takes an Enum type as the method parameter. The code looks something like this:
String value = "EnumValue1";
Method setter = getBeanWriteMethod("setMyEnumValue");
Class<?> type = setter.getParameterTypes()[0];
Object convertedValue = null;
if (type.isEnum()) {
convertedValue = convertToEnum(value, type);
} else {
convertedValue = ClassUtils.convertType(value, type);
}
return convertedValue;
The question is what to put in the convertToEnum method. I know I could "brute force it" by iterating the enum constants (or the fields) of the type object, matching the value. Am I overlooking a simpler way to do it using Reflection? (I looked at several examples, but didn't find any where the enum was only know via Class).
Off the top of my head:
Enum<?> convertedValue = Enum.valueOf((Class<Enum>)type, value);
This will convert a string to an enum constant of the Enum class of type
Edit: Now that I have a computer handy, I can see what actually works. Either of the below cases ran correctly without compiler warnings:
Enum<?> convertedValueA = Enum.valueOf(type, value);
Enum<?> convertedValueB = Enum.valueOf(type.asSubclass(Enum.class), value);
The second one calls asSubClass() which would do a runtime check to ensure that type is some enum class, but the valueOf() method has to make that check anyway in order to work correctly.
The following gave me a compile error:
Enum<?> convertedValueC = Enum.valueOf((Class<? extends Enum <?>>)type, value);
java: Foo.java:22: <T>valueOf(java.lang.Class<T>,java.lang.String) in java.lang.Enum cannot be applied to (java.lang.Class<capture#134 of ? extends java.lang.Enum<?>>,java.lang.String)
The intricacies of casting to wildcard types confuses me so I've probably tried the wrong cast. Plus the fact that it has no runtime effect means that it's easy to get it wrong and never find out.
You can use
Class enumType = ....
String name = ....
Enum e = Enum.valueOf(enumType, name);
e.g.
import java.lang.annotation.*;
public class Main {
public static void main(String[] args) {
Class enumType = RetentionPolicy.class;
String name = "SOURCE";
Enum e = Enum.valueOf(enumType, name);
System.out.println(e);
}
}
prints
SOURCE
Enum.valueOf(yrEnum, myString)
Returns the enum where myString is the name of the enum instance you want.
And yrEnum.values() returns an array of all the different possible Enums instances.
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()
How do I create a reference to a constant object?
final Myclass obj = new Myclass();
does not work, it says obj(the reference) should not be re-assigned but we can still change the object referred. I want to ensure that the object itself does not change once constructed.
Just make it immutable (like String is). Or wrap it in another object which restricts access to mutators of the object in question (like Collections.unmodifiableList() and consorts do).
You are mixing two things: final and immutable.
A variable can be final, so you can't change it's a value (or object reference) after it is initialized (but of course you can change the reference's objects attributes)
An object can be immutable (not a keyword but a property), so you can't change it's value after it is created. The string is a good example - you can not change the backing char[] inside a String object.
What you want is an Immutable Object. There are no keywords in Java that can instantly make an object immutable. You have to design the object's logic, so that its state cannot be changed. As BalusC put, you can wrap it in another object which restricts access to its mutators.
I don't think there's any built in keyword to make that possible in Java. Even if the reference is constant/final, the internals of the object could still be changed.
Your best options is to have a ReadOnly implementation version of your class.
You can read more about this here: http://en.wikipedia.org/wiki/Const-correctness#final_in_Java
In Java, an immutable class is generally means that it doesn't have "setters" and any field that can be accessed with a "getter" should also be immutable. In order to get your data into the class to start, you'll need to have a constructor that takes the values as arguments:
public class MyClass {
String something;
int somethingElse;
// The class can only be modified by the constructor
public MyClass(String something, int somethingElse) {
this.something = something;
this.somethingElse = somethingElse;
}
// Access "something". Note that it is a String, which is immutable.
public String getSomething() {
return something;
}
// Access "somethingElse". Note that it is an int, which is immutable.
public int getSomethingElse() {
return somethingElse;
}
}
Yes it does you seem to have forgotten to set the type.
final MyClass obj = new Myclass();
That means that obj can only be assigned once. Java does not have a const keyword like C++ does. If MyClass is not declared final (final class MyClass { ... }) it can still change.
final variables should be assigned in the moment of declaration.
final MyClass obj = new MyClass();
In java object constant means you cannot change its reference but you can change the values of its state variables untill they are not final. if all the member variables are final then its a perfect constant, where you cannot change anything.
Here is a way to wrap any object to make it "roughly" immutable.
All method calls that are not 'getters' will throw an Exception. This code defines a getter as a method that meets these criteria:
name of the method starts with get or is
it takes no arguments
it returns a value (not void return type)
Yes, getter methods could mutate an object. But if your code (or code you are using) is doing that, you have some bigger problems, please go get some help :)
the code:
class ImmutableWrapper
public static <T> T wrap(T thing) {
return (T) Proxy.newProxyInstance(thing.getClass().getClassLoader(), new Class[]{thing.getClass()}, OnlyGettersInvocationHandler.instance);
}
private static class OnlyGettersInvocationHandler implements InvocationHandler {
public static InvocationHandler instance;
#Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
final String name = method.getName();
if ((args == null || args.length == 0)
&& (name.startsWith("get") || name.startsWith("is")
&& !method.getReturnType().equals(Void.class))) {
return method.invoke(proxy, args);
} else {
throw new UnsupportedOperationException("immutable object: " + proxy + ", cannot call " + name);
}
}
}
}
SomeClass myThing = ... create and populate some object ...
SomeClass myImmutableThing = ImmutableWrapper.wrap(myThing);
myImmutableThing.setValue('foo'); // throws Exception
myImmutableThing.whatever(); // throws Exception
myImmutableThing.getSomething(); // returns something
myImmutableThing.isHappy(); // returns something
Mayby you can create class with final attributes. So, you can't change it: object == const.
At least "String" immutable because of it:
public final class String implements Serializable, Comparable<String>, CharSequence {
private final char[] value;
//...
}