Currently I have classes with several nested classes inside is, like:
public class Foo {
private Bar bar;
//getter & setter
public class Bar {
private Abc abc;
//getter & setter
public class Abc {
#RequiredParam
private String property;
//getter & setter
}
}
}
I am trying to get the value of the fields but I am having a hard time how to achieve this.
So far I have:
public static boolean isValid(Object paramClazz) throws Exception {
List<Class> classes = new ArrayList<>();
getClasses(classes, paramClazz.getClass());
for (Class clazz : classes) {
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(RequiredParam.class)) {
field.setAccessible(true);
//how to get the value? field.get(paramClazz) doesn't work
}
}
}
return true;
}
private static void getClasses(List<Class> classes, Class<?> clazz) {
if (clazz.getDeclaredClasses().length > 0) {
for (Class<?> c : clazz.getDeclaredClasses()) {
getClasses(classes, c);
}
}
classes.add(clazz);
}
My goal is to the able to check if the field annotated with #RequiredParam is not null, so I have the method isValid() which will received an object and should be able to check all fields (even the ones inside nested classes) and see if any is missing.
The problem is when I try to call field.get() and I don't know which object I am supposed to pass to this method. Passing the highest level object won't work, because I need somehow to pass only the Abc object to the method.
How can I get the correct object to pass to the field.get() call, considering I can have more or less nested levels in my classes?
This is an example code that scans all fields of an object recursively until it finds values of all annotated fields:
public static Collection<Object> getAnnotatedValues(final Object root) throws ReflectiveOperationException {
return getAnnotatedValues(root, new HashSet<>());
}
private static Collection<Object> getAnnotatedValues(final Object root, final Set<Object> inspected)
throws ReflectiveOperationException {
final List<Object> annotatedValues = new ArrayList<>();
if (inspected.contains(root)) { // Prevents stack overflow.
return Collections.EMPTY_LIST;
}
inspected.add(root);
for (final Field field : gatherFields(root.getClass())) {
field.setAccessible(true);
final Object currentValue = field.get(root);
field.setAccessible(false);
if (field.isAnnotationPresent(RequiredParam.class)) {
// Found required value, search finished:
annotatedValues.add(currentValue);
if (currentValue != null) {
inspected.add(currentValue);
}
} else if (currentValue != null) {
// Searching for annotated fields in nested classes:
annotatedValues.addAll(getAnnotatedValues(currentValue, inspected));
}
}
return annotatedValues;
}
private static Iterable<Field> gatherFields(Class<?> fromClass) {
// Finds ALL fields, even the ones from super classes.
final List<Field> fields = new ArrayList<>();
while (fromClass != null) {
fields.addAll(Arrays.asList(fromClass.getDeclaredFields()));
fromClass = fromClass.getSuperclass();
}
return fields;
}
You might have implemented something similar, but had trouble getting to the last nested class. This is because Field instance is just a description of a class and (unless the field is static) it needs an actual instance the be able to extract a value. From Field#get(Object) method docs:
If the underlying field is a static field, the obj argument is ignored; it may be null.
Otherwise, the underlying field is an instance field. If the specified obj argument is null, the method throws a NullPointerException. If the specified object is not an instance of the class or interface declaring the underlying field, the method throws an IllegalArgumentException.
If you did not initiate fields in your class structure, you would have a hard time extracting a value - even if you found annotated fields, you would still need an instance of the class to extract them. For example, given these classes:
public class Foo {
private final Bar bar = new Bar();
public class Bar {
private final Abc abc = new Abc();
public class Abc {
#RequiredParam private final String property = "Result.";
}
}
#Retention(RetentionPolicy.RUNTIME)
public static #interface RequiredParam {}
}
...getAnnotatedValues(new Foo()) returns collection containing "Result.". You can easily modify the methods to fit your needs (for example, return true as soon as the first valid annotated field is found or simply return false if the collection is empty/contains nulls).
Related
How can I set or get a field in a class whose name is dynamic and stored in a string variable?
public class Test {
public String a1;
public String a2;
public Test(String key) {
this.key = 'found'; <--- error
}
}
You have to use reflection:
Use Class.getField() to get a Field reference. If it's not public you'll need to call Class.getDeclaredField() instead
Use AccessibleObject.setAccessible to gain access to the field if it's not public
Use Field.set() to set the value, or one of the similarly-named methods if it's a primitive
Here's an example which deals with the simple case of a public field. A nicer alternative would be to use properties, if possible.
import java.lang.reflect.Field;
class DataObject
{
// I don't like public fields; this is *solely*
// to make it easier to demonstrate
public String foo;
}
public class Test
{
public static void main(String[] args)
// Declaring that a method throws Exception is
// likewise usually a bad idea; consider the
// various failure cases carefully
throws Exception
{
Field field = DataObject.class.getField("foo");
DataObject o = new DataObject();
field.set(o, "new value");
System.out.println(o.foo);
}
}
Class<?> actualClass=actual.getClass();
Field f=actualClass.getDeclaredField("name");
The above code would suffice .
object.class.getField("foo");
Unfortunately the above code didn't work for me , since the class had empty field array.
I'm stuck on this problem for almost 3 months now and just can't resolve it myself. I hope it's possible. I'm trying to inject this code with my own custom entity class, which is hard to access, because the class is static and the field is final. Somehow i'm not sure if the generic type is a problem on accessing it.
public class EntityTypes<T extends Entity> {
private final EntityTypes.b<T> aZ;
[some code here]
public interface b<T extends Entity> {
T create(EntityTypes<T> entitytypes, World world);
}
public static class a<T extends Entity> {
private final EntityTypes.b<T> a;
[more code here]
}
}
So far i tried to use Reflections, but i keep getting:
java.lang.IllegalArgumentException: Can not set net.server.EntityTypes$b field net.server.EntityTypes$a.a to net.server.EntityTypes
That is my running code:
// works
ReflectionUtils.setFinal(EntityTypes.class, EntityTypes.VILLAGER, "aZ", (EntityTypes.b<CustomVillager>) CustomVillager::new);
// while this does not work!
ReflectionUtils.setFinal(EntityTypes.a.class, EntityTypes.VILLAGER, "a", (EntityTypes.b<CustomVillager>) CustomVillager::new);
public class ReflectionUtils {
// Does only work on Java 12 and above!!
public static void setFinal(Class cls, Object obj, String fieldName, Object value) {
try {
Field field = cls.getDeclaredField(fieldName);
FieldHelper.makeNonFinal(field);
field.setAccessible(true);
field.set(obj, value);
} catch (Exception e) {
e.printStackTrace();
}
}
// For Java 12 final field injection
// https://stackoverflow.com/questions/56039341/get-declared-fields-of-java-lang-reflect-fields-in-jdk12/
public final static class FieldHelper {
private static final VarHandle MODIFIERS;
static {
try {
var lookup = MethodHandles.privateLookupIn(Field.class, MethodHandles.lookup());
MODIFIERS = lookup.findVarHandle(Field.class, "modifiers", int.class);
} catch (IllegalAccessException | NoSuchFieldException ex) {
throw new RuntimeException(ex);
}
}
public static void makeNonFinal(Field field) {
int mods = field.getModifiers();
if (Modifier.isFinal(mods)) {
MODIFIERS.set(field, mods & ~Modifier.FINAL);
}
}
}
}
public class CustomVillager extends EntityVillager {
public CustomVillager(EntityTypes<? extends CustomVillager> entityTypes, World world) {
super(entityTypes, world);
}
}
The exception you are getting means that the Field object represents a field on a class that is different than the class of the the object you are trying to set it on. So in your setFinal() method, you get a Field object representing the field named fieldName on the class cls, and then you try to set that field on the object obj. That means that the object passed in as obj must be an instance of the class cls, or otherwise it won't work.
Looking at the two lines that call setFinal(), the first gets the field aZ in EntityTypes class; this field only exists on an instance of EntityTypes. The second setFinal() call gets the field a in the EntityTypes.a class; this field only exists on an instance of EntityTypes.a. You try to set both of these fields on EntityTypes.VILLAGER. You have not shown the code that declares or initializes EntityTypes.VILLAGER, so we don't know what it is, but these two lines would only work if EntityTypes.VILLAGER were both an instance of EntityTypes and an instance of EntityTypes.a, which is impossible (since they are both classes, neither is a subclass of the other, and Java does not have double inheritance of classes). So one of these two lines must be wrong.
How can I set or get a field in a class whose name is dynamic and stored in a string variable?
public class Test {
public String a1;
public String a2;
public Test(String key) {
this.key = 'found'; <--- error
}
}
You have to use reflection:
Use Class.getField() to get a Field reference. If it's not public you'll need to call Class.getDeclaredField() instead
Use AccessibleObject.setAccessible to gain access to the field if it's not public
Use Field.set() to set the value, or one of the similarly-named methods if it's a primitive
Here's an example which deals with the simple case of a public field. A nicer alternative would be to use properties, if possible.
import java.lang.reflect.Field;
class DataObject
{
// I don't like public fields; this is *solely*
// to make it easier to demonstrate
public String foo;
}
public class Test
{
public static void main(String[] args)
// Declaring that a method throws Exception is
// likewise usually a bad idea; consider the
// various failure cases carefully
throws Exception
{
Field field = DataObject.class.getField("foo");
DataObject o = new DataObject();
field.set(o, "new value");
System.out.println(o.foo);
}
}
Class<?> actualClass=actual.getClass();
Field f=actualClass.getDeclaredField("name");
The above code would suffice .
object.class.getField("foo");
Unfortunately the above code didn't work for me , since the class had empty field array.
How to check if given class has specific field and if it is initialized (has value at the moment)?
abstract class Player extends GameCahracter {
}
public class Monster extends GameCahracter{
public int level = 1;
}
abstract class GameCharacter{
public void attack(GameCahracter opponent){
if (opponent instanceof Monster && ){ // << here I have to know is it instance of Monster and if it has initialized value
}
}
To see if a class has a property without rely on exception, you can use these methods:
private Boolean objectHasProperty(Object obj, String propertyName){
List<Field> properties = getAllFields(obj);
for(Field field : properties){
if(field.getName().equalsIgnoreCase(propertyName)){
return true;
}
}
return false;
}
private static List<Field> getAllFields(Object obj){
List<Field> fields = new ArrayList<Field>();
getAllFieldsRecursive(fields, obj.getClass());
return fields;
}
private static List<Field> getAllFieldsRecursive(List<Field> fields, Class<?> type) {
for (Field field: type.getDeclaredFields()) {
fields.add(field);
}
if (type.getSuperclass() != null) {
fields = getAllFieldsRecursive(fields, type.getSuperclass());
}
return fields;
}
And simply call:
objectHasProperty(objInstance, "myPropertyName");
In fact does not matter the instance of the class to see if the class has the property, but I made that way, just to be little more friendly.
Just to conclude: I made the getAllFields to be recursive, to get all the superclasses methods too (in my case this is important)
After that, if you want to see what is the value of the property in the desired object, you can just call:
PropertyUtils.getProperty(objInstance, "myPropertyName");
Remember: if objInstance does not have that property, the call above will throw NoSuchMethodException (That is why you need to use the fist code to see if the class has the property)
You can use reflection, for example like this:
Class.forName("Foo").getFields()
And then you can check again if particular object has this field initialiazed by using reflection.
You do not have to use reflection for this you can simply do it with if condition.
if (opponent !=null && opponent instanceof Monster && ((Monster) opponent).level==1){ // << here I have to know is it instance of Monster and if it has initialized value
}
You can check the instance is not null if instance not null and its an instance of Monster then in your case its definitely initialized. Instance Variables initialized with default values whenever a new instance created if the opponent instance of a monster then level has value 1.
In addition to the answer of #Renato Lochetti i want to add a variant with only a single function, not using 3:
private boolean hasField(final Class<?> clazz, final String fieldName) {
// gather all fields of this class
final List<Field> fields = new ArrayList<>();
Class<?> current = clazz;
do {
Collections.addAll(fields, current.getDeclaredFields());
} while ((current = clazz.getSuperclass()) != null);
// check if field exists
return fields.stream().map(Field::getName).anyMatch(f -> f.equals(fieldName));
}
//Load the class
Class clazz = Class.forName("your.class.ClassName");
Field field = clazz.getField("fieldName")
if(field!=null){
//field exist now check if its initialized or not, or if its primitive field check against its assumed initialized value
if(ClassName.fieldName!=null){
//yes initilized
}
}
I want to create something that resembles an extendable Enum (understanding extending Enums isn't possible in Java 6).
Here is what im trying to do:
I have many "Model" classes and each of these classes have a set of Fields that are to be associated with it. These Fields are used to index into Maps that contain representations of the data.
I need to be able to access the Fields from an Class OR instance obj as follows:
MyModel.Fields.SOME_FIELD #=> has string value of "diff-from-field-name"
or
myModel.Fields.SOME_FIELD #=> has string value of "diff-from-field-name"
I also need to be able to get a list of ALL the fields for Model
MyModel.Fields.getKeys() #=> List<String> of all the string values ("diff-from-field name")
When defining the "Fields" class for each Model, I would like to be able to keep the definition in the same file as the Model.
public class MyModel {
public static final Fields extends BaseFields {
public static final String SOME_FIELD = "diff-from-field-name";
public static final String FOO = "bar";
}
public Fields Fields = new Fields();
// Implement MyModel logic
}
I also want to have OtherModel extends MyModel and beable to inherit the Fields from MyModel.Fields and then add its own Fields on top if it ..
public class OtherModel extends MyModel {
public static final class Fields extends MyModel.Fields {
public static final String CAT = "feline";
....
Which woulds allow
OtherModel.Fields.CAT #=> feline
OtherModel.Fields.SOME_FIELD #=> diff-from-field-name
OtherModel.Fields.FOO #=> bar
OtherModel.Fields.getKeys() #=> 3 ["feline", "diff-from-field-name", "bar"]
I am trying to make the definition of the "Fields" in the models as clean and simple as possible as a variety of developers will be building out these "Model" objects.
Thanks
I need to be able to access the Fields from an Class OR instance obj as follows:
MyModel.Fields.SOME_FIELD #=> has string value of "diff-from-field-name"
That is not possible in Java unless you use a real enum or SOME_FIELD is a real field. In either case, the "enum" is not extensible.
The best you can do in Java 6 is to model the enumeration as mapping from String names to int values. That is extensible, but the mapping from names to values incurs a runtime cost ... and the possibility that your code will use a name that is not a member of the enumeration.
The reason that enum types in Java are not extensible is that the extended enum would break the implicit invariants of the original enum and (as a result) could not be substitutable.
I've just tried out some code trying to do what you've just described and it was really cumbersome.
If you have a Fields static inner class somewhere in a model class like this:
public class Model {
public static class Fields {
public static final String CAT = "cat";
protected static final List<String> KEYS = new ArrayList<String>();
static {
KEYS.add(CAT);
}
protected Fields() {}
public static List<String> getKeys() {
return Collections.unmodifiableList(KEYS);
}
}
}
and you extend this class like this:
public class ExtendedModel extends Model {
public static class ExtendedFields extend Model.Fields {
public static final String DOG = "dog";
static {
KEYS.add(DOG);
}
protected ExtendedFields() {}
}
}
then its just wrong. If you call Model.Fields.getKeys() you'd get what you expect: [cat], but if you call ExtendedModel.ExtendedFields.getKeys() you'd get the same: [cat], no dog. The reason: getKeys() is a static member of Model.Fields calling ExtendedModel.ExtendedFields.getKeys() is wrong because you really call Model.Fields.getKeys() there.
So you either operate with instance methods or create a static getKeys() method in all of your Fields subclasses, which is so wrong I can't even describe.
Maybe you can create a Field interface which your clients can implement and plug into your model(s).
public interface Field {
String value();
}
public class Model {
public static Field CAT = new Field() {
#Override public String value() {
return "cat";
}
};
protected final List<Field> fields = new ArrayList();
public Model() {
fields.add(CAT);
}
public List<Field> fields() {
return Collections.unmodifiableList(fields);
}
}
public class ExtendedModel extends Model {
public static Field DOG= new Field() {
#Override public String value() {
return "dog";
}
};
public ExtendedModel() {
fields.add(DOG);
}
}
I wonder whether you really need a generated enumeration of fields. If you are going to generate a enum of a list the fields based on a model, why not generate a class which lists all the fields and their types? i.e. its not much harder to generate classes than staticly or dynamically generated enums and it much more efficient, flexible, and compiler friendly.
So you could generate from a model something like
class BaseClass { // with BaseField
String field;
int number;
}
class ExtendedClass extends BaseClass { // with OtherFields
String otherField;
long counter;
}
Is there a real benefit to inventing your own type system?
I was able to come up with a solution using reflection that seems to work -- I haven't gone through the full gamut of testing, this was more me just fooling around seeing what possible options I have.
ActiveField : Java Class which all other "Fields" Classes (which will be inner classes in my Model classes) will extend. This has a non-static method "getKeys()" which looks at "this's" class, and pulled a list of all the Fields from it. It then checks a few things like Modifiers, Field Type and Casing, to ensure that it only looks at Fields that match my convention: all "field keys" must be "public static final" of type String, and the field name must be all UPPERCASE.
public class ActiveField {
private final String key;
protected ActiveField() {
this.key = null;
}
public ActiveField(String key) {
System.out.println(key);
if (key == null) {
this.key = "key:unknown";
} else {
this.key = key;
}
}
public String toString() {
return this.key;
}
#SuppressWarnings("unchecked")
public List<String> getKeys() {
ArrayList<String> keys = new ArrayList<String>();
ArrayList<String> names = new ArrayList<String>();
Class cls;
try {
cls = Class.forName(this.getClass().getName());
} catch (ClassNotFoundException e) {
return keys;
}
Field fieldList[] = cls.getFields();
for (Field fld : fieldList) {
int mod = fld.getModifiers();
// Only look at public static final fields
if(!Modifier.isPublic(mod) || !Modifier.isStatic(mod) || !Modifier.isFinal(mod)) {
continue;
}
// Only look at String fields
if(!String.class.equals(fld.getType())) {
continue;
}
// Only look at upper case fields
if(!fld.getName().toUpperCase().equals(fld.getName())) {
continue;
}
// Get the value of the field
String value = null;
try {
value = StringUtils.stripToNull((String) fld.get(this));
} catch (IllegalArgumentException e) {
continue;
} catch (IllegalAccessException e) {
continue;
}
// Do not add duplicate or null keys, or previously added named fields
if(value == null || names.contains(fld.getName()) || keys.contains(value)) {
continue;
}
// Success! Add key to key list
keys.add(value);
// Add field named to process field names list
names.add(fld.getName());
}
return keys;
}
public int size() {
return getKeys().size();
}
}
Then in my "Model" classes (which are fancy wrappers around a Map, which can be indexed using the Fields fields)
public class ActiveResource {
/**
* Base fields for modeling ActiveResource objs - All classes that inherit from
* ActiveResource should have these fields/values (unless overridden)
*/
public static class Fields extends ActiveField {
public static final String CREATED_AT = "node:created";
public static final String LAST_MODIFIED_AT = "node:lastModified";
}
public static final Fields Fields = new Fields();
... other model specific stuff ...
}
I can then make a class Foo which extends my ActiveResource class
public class Foo extends ActiveResource {
public static class Fields extends ActiveResource.Fields {
public static final String FILE_REFERENCE = "fileReference";
public static final String TYPE = "type";
}
public static final Fields Fields = new Fields();
... other Foo specific stuff ...
Now, I can do the following:
ActiveResource ar = new ActiveResource().
Foo foo = new Foo();
ar.Fields.size() #=> 2
foo.Fields.size() #=> 4
ar.Fields.getKeys() #=> ["fileReference", "type", "node:created", "node:lastModified"]
foo.Fields.getKeys() #=> ["node:created", "node:lastModified"]
ar.Fields.CREATED_AT #=> "node:created"
foo.Fields.CREATED_AT #=> "node:created"
foo.Fields.TYPE #=> "type"
etc.
I can also access the Fields as a static field off my Model objects
Foo.Fields.size(); Foo.Fields.getKeys(); Foo.Fields.CREATED_AT; Foo.Fields.FILE_REFERENCE;
So far this looks like a pretty nice solution, that will require minimal instruction for building out new Models.
Curses - For some reason my very lengthy response with the solution i came up with did not post.
I will just give a cursory overview and if anyone wants more detail I can re-post when I have more time/patience.
I made a java class (called ActiveField) from which all the inner Fields inherit.
Each of the inner field classes have a series of fields defined:
public static class Fields extends ActiveField {
public static final String KEY = "key_value";
}
In the ActiveRecord class i have a non-static method getKeys() which uses reflection to look at the all the fields on this, iterates through, gets their values and returns them as a List.
It seems to be working quite well - let me know if you are interested in more complete code samples.