Is there any way to get a Field reference from an instance (not from a class) ?
This is an example :
public class Element {
#MyAnnotation("hello")
public String label1;
#MyAnnotation("world")
public String label2;
}
public class App {
private Element elem = new Element();
public void printAnnotations() {
String elemLabel1 = elem1.label;
String elemLabel2 = elem2.label;
// cannot do elemLabel.getField().getDeclaredAnnotations();
String elemLabel1AnnotationValue = // how ?
String elemLabel2AnnotationValue = // how ?
}
}
Sorry for not being too clear, but i already know how to fetch Fields from a class (Class --> Field --> DeclaredAnnotations)
What i am wondering is how to get the Field for a particular instance.
In this example, from elemLabel1 string instance, i wish to be able to get the Field of Element.label1.
What exactly do you mean? A Field on defined on the Class. You can get the value for a specific instance:-
private static class Test {
private int test = 10;
}
public static void main(String[] args) throws Exception {
final Test test = new Test();
final Field field = Test.class.getDeclaredField("test");
field.setAccessible(true);
final int value = field.getInt(test);
System.out.println(value);
}
The the class Test has a Field called test. This is true of any Test - it is defined in the Class. The instance of the class is has a specific value for that Field, in this case 10. This can retrieved for a specific instance using the getXXX or get method.
EDIT
From the code in your question it looks like you want the value of an Annotation field not the value of a class field.
In Java, values in annotations are compile time constants and therefore are also defined at the class rather than instance level.
public class Element {
#MyAnnotation("l")
public String label;
}
In your example, the MyAnnotation value field must be equal to 1 for every instance of Element.
Field belongs to class. Therefore you actually want to do the following:
elemLabel.getClass().getField("theFieldName").getDeclaredAnnotations();
However although your field is public typically all fields should be private. In this case use getDeclaredField() instead of getField().
EDIT
you have to call field.setAccessible(true) before using the field.
Related
I am having one class which is having getter and setter methods i am storing that getter method in mongodb with some other collection. After getting the method name from DB how to access that method. Whether it is possible to do like this or not?
public class MappingAlgorithmScoreGenerationRules {
#Field(value = FieldNames.CATEGORY)
private String category;
#Field(value = FieldNames.ATTRIBUTE_NAME)
private MappingScoreGenerationLogic attributeName;
#Field(value = FieldNames.PRIORITY)
private Integer priority;
#Field(value = FieldNames.ATTRIBUTE_SCORE)
private Integer attributeScore;
#Field(value = FieldNames.FINAL_THRESHOLD)
private Integer finalThreshold;
#Field(value = FieldNames.RESULT_COUNT)
private Integer resultCount;
#Field(value = FieldNames.NORMALIZED_VALUE)
private Integer normalizedValue;
#Field(value = FieldNames.GETTER_METHOD)
private String getterMethod;
}
This is the class where i am storing the method name.
public class MatchEntry {
private double matchedWeight;
public double getMatchedWeight() {
return matchedWeight;
}
public void setMatchedWeight(double matchedWeight) {
this.matchedWeight = matchedWeight;
}
}
getMatchedWeight is the method name i am going to store in the DB MappingAlgorithmScoreGenerationRules.
After getting the method name how to access the method name?
I want to access like
For example: MatchEntry.(the value get from db)
Use reflection API - https://docs.oracle.com/javase/tutorial/reflect/member/methodInvocation.html
Method methodToInvoke
= MatchEntry.class.getMethod("methodName", methodParams,..);
methodToInvoke.invoke(matchEntryInstance, params,..);
In Java you can achieve method access by name using reflection (https://docs.oracle.com/javase/tutorial/reflect/member/methodInvocation.html).
This is a tutorial you may be able to use to lean more about this language feature: https://www.geeksforgeeks.org/reflection-in-java/
In your example, let's say you have loaded an instance of MappingAlgorithmScoreGenerationRules from the database, whose getterMethod attribute returns "getMatchedWeight".
Let's also assume that you have an instance of MatchEntry.
You would then access as follows:
MappingAlgorithmScoreGenerationRules rules = ....; //load from DB
MatchEntry entry = ...; //wherever it comes from
String getterMethodName = rules.getGetterMethod();
Method getter = MatchEntry.class.getMethod(getterMethodName);
Object value = getter.invoke(entry);
This code snippet omits Exceptions, in particular NoSuchMethodException and InvocationTargetException.
Please note that if you choose this approach, and depending heavily on the rest of your domain model, you will also need to be very careful with assumptions about the return type of the actual value (unless you can somehow guarantee that they are all the same, in which case you could cast the value).
Code that uses reflection is also inherently brittle and prone to failure as soon as you refactor. Imagine you have a populated database with these rules, and during a code review a couple of methods are renamed. Inoccuous change? Or will your entire setup break on the next deploy?
A (type-)safer approach might be to ensure all entries and related objects derive from an interface that standardises the return type on a getValue(String attributeName) method, so instead of messing with reflection you might do:
MappingAlgorithmScoreGenerationRules rules = ....; //load from DB
MatchEntry entry = ...; //wherever it comes from
String attributeName = rules.getAttribute(); //instead of 'getterMethod'
Object value = entry.getValue(attributeName);
where MatchEntry.getValue might be defined as:
public Object getValue(String attribute) {
switch(attribute) {
case "matchedWeight": return getMatchedWeight();
default: return null; //or you could throw an exception
}
}
This would easily survive any kind of method name refactoring and reorganisation, but adds the overhead of adding a case to the switch for every new attribute.
This problem could be partially solved with a runtime annotation that essentially binds an attribute name to a getter method, e.g.:
public class MatchEntry implements Matchable {
private double matchedWeight;
#MyCustomAnnotation("matchedWeight")
public double getMatchedWeight() {
return matchedWeight;
}
public void setMatchedWeight(double matchedWeight) {
this.matchedWeight = matchedWeight;
}
}
public interface Matchable {
default Object getValue(String attributeName) {
//read methods annotated with 'MyCustomAnnotation's in current class and call the one with matching value
}
}
Your getValue(String attributeName) would be tasked with reading these annotations and dynamically figuring out which getter to call. Still requires the annotation to be added everywhere it's needed, but at least it's with the getter and not hidden in some switch that's potentially duplicated across multiple class definitions.
Instead you just need a single default definition in the parent interface, as hinted above.
public String processName() throws Exception {
String name = dbManager.getName(); // getname
String connection = dbManager.getConnection();
String name2 = dbManager.getName();
Mydata mydata = new Mydata();
String getData = mydata.getGetData();
List<String> list = dbManager.getList();
return getData.toLowerCase();
}
private class Mydata {
String getData = "test";
public String getGetData() {
return getData;
}
public void setGetData(String getData) {
this.getData = getData;
}
}
In general, you should not be using private classes and avoid writing the tests for them as they are supposed to be black-boxes for the outer world.
But still if you are using one and want to mock it then here is how you can do it using JMockit:
Object ins = Deencapsulation.newInnerInstance("Mydata", outerClass.class, (Object[]) null);
I have used null because you have not defined any constructor on your inner private class.
Here is the documentation if you are interested:
Object mockit.Deencapsulation.newInnerInstance(String
innerClassSimpleName, Object outerClassInstance, Object...
nonNullArgs)
The same as newInstance(String, Class[], Object), but for
instantiating an inner non-accessible class of some other class, and
where all other (if any) initialization arguments are known to be
non-null.
Parameters:
innerClassSimpleName:
the inner class simple name, that is, the part after the "$" character in its full name
outerClassInstance:
the outer class instance to which the inner class instance will belong
nonNullArgs:
zero or more non-null parameter values for the invocation; if a null value needs to be passed, the Class object for the
corresponding parameter type must be passed instead type to which
the returned instance should be assignable
Returns: a newly created instance of the specified inner class, initialized > with the given arguments
Throws: IllegalArgumentException - if a null reference was provided for a parameter
I have some class with constant to test:
public class SomeClass {
private static final String SOME_CONST = "blabla";
And I have to use it in test, so I make (with Spring ReflectionUtils and java.lang native arsenal) smth like:
findField(SomeClass.class, "SOME_CONST").setAccessible(true);
or
makeAccessible(findField(SomeClass.class, "SOME_CONST"));
Running test
#Test
public void someTest() throws Exception {
String s = SomeClass.SOME_CONST;
I see my Intellij Idea stops running with error related with trying to access private field. Suppose I should use some kind of #SuppressWarnings or how to solve such an issue better?
Testing private methods/fields is usually sign of bad design.
If you don't mind to show it around, set it public or put a getter to retrieve that variable, since it's final you should not have any trouble unless it has sensitive data or it's a mutable class (not the case of a String).
Or using your approach, do
Field field = TargetClass.getDeclaredField(fieldName);
field.setAccessible(true);
String someConst = (String) field.get(new SomeClass());
following this hint
As were mentioned above we can (or even should) change private fields of tested class to public, but in case you are not able to do so you can use my soulution (I tried to avoid extra fields in test class, but nobody suggested solution to my question):
private String EXTRA_FIELD_TO_HOLD_CONSTANT_VALUE_FROM_TESTED_CLASS;
#Before
public void setUp() throws Exception {
EXTRA_FIELD_TO_HOLD_CONSTANT_VALUE_FROM_TESTED_CLASS =
getPrivateStringConstantValue("SOME_CONST");
}
private String getPrivateStringConstantValue(String fieldName) throws IllegalAccessException {
Field field = findField(CtcFraudIPAddressListServiceImpl.class, fieldName);
field.setAccessible(true);
return field.get(testedService).toString();
}
I am trying to learn Java by my self and i am making a game you all properly know, which is Monopoly.
I have searched for my answer but couldnt find it, so here it is.
I have a class Field with two variables fieldnumber and fieldname. My idea is to make a field with a number, so the program know where the players are (not relevant now).
The fieldname and fieldnumbershould only be readable (means not editable) after the program have created the fields and names for the fields.
I need to know how i can intialize these two variables into a contructor and make the variables to be only "getters", so they cant be changed later on.
(obs: the class Field is only a subclass, i need to use the data in the main class later on)
Im a bit confused and tried to read the book i am using, but no luck.
Declare the fields final, assign them in constructor and do not write setters.
Should the number of properties increase, you may consider using builder pattern to avoid constructor with many arguments.
class Field {
private final int fieldNumber;
private final String fieldName;
public Field(final int fieldNumber, final String fieldName) {
// you may validate the values here and throw exception in case of non-valid values
this.fieldNumber = fieldNumber;
this.fieldName = fieldName;
}
public int getFieldNumber() {
return fieldNumber;
}
public String getFieldName() {
return fieldName;
}
}
I suggest to make the two attribut as private (not accessible), initialize them when creating the instance, and you can use the getter to get their values:
class Field{
private String fieldname;
private int fieldnumber;
public Field (String fieldname, int fieldnumber)
{
this.fieldname = fieldname;
this.fieldnumber= fieldnumber;
}
public String getFieldname(){
return fieldname;
}
public int getFieldnumber(){
return fieldnumber;
}
public String toString(){
return fieldnumber+ " " +fieldname;
}
public boolean equals(Object obj){
Field field = (Field) obj;
return (fieldnumber == field.fieldnumber && fieldname.equals(field.fieldname);
}
}
A "getter" is a method that returns the value of your field.
A "setter" is a method typically taking one argument, setting the value of your field (possibly after some validation).
For good encapsulation, your instance fields should typically only be accessed within the maximum scope allowed within context (typically private fields with getters/setters, sometimes protected or package-protected fields when inheritance or more complex settings are required)
A field marked with the final non-access modifier can only be assigned once
In your case, if the fields are scoped within the instance of your class, but will never change once assigned, you can mark them final and assign them in a constructor or instance statement (no setters).
If they are not bound to an instance, but rather to the class, then you can mark them constant (static final) and assign them right away (you can then safely make them public if they are immutable - i.e. Strings or primitives)
Getter means a method that returns a value an object stores. A variable being a getter doesn't mean anything. Getters are usually used to get variables that are declared private; that is, variables that are not 'visible' from outside the class. See the example:
class Example {
private int value;
public Example(int valueToBeSet) {
this.value = valueToBeSet;
}
}
In the above example, the variable value is only visible from the class Example; any other class cannot get that variable. This is useful when you want that no other class is able to change its value. However, to get the value from the object, you use a getter:
class Example {
private int value;
public Example(int valueToBeSet) {
this.value = valueToBeSet;
}
public int getValue() {
return this.value;
}
}
Here the method getValue() is a getter. You cannot change the value, because it is private, but you can call the method getValue(), and get the value, because the method is public.
Other way to assign a variable's value, be able to get its value, but not be able to change it, is to use the final keyword:
class Example {
public final int value;
public Example(int valueToBeSet) {
this.value = valueToBeSet;
}
}
This way the variable's value can only be set once, in the constructor, and never again. However, you can still get the value from outside the class because it is public. This is often a good way to do things, however it has its downsides; namely as I explained, you cannot change the value anymore, and to get an object with a different value, you would have to create a new object altogether. This is the closest you can get to a "getter variable".
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.