Access static final variable using reflection - java

I have a Java class with a static variable
package com.mytest
public class MyClass{
public static final TextClass TEXT_CLASS = new TextClass();
}
How can I access the object TEXT_CLASS using reflection?
(I have the string "com.mytest.MyClass.TEXT_CLASS". I need to access the object.)

Accessing static fields is done exactly the same way as normal fields, only you don't need to pass any argument to Field.get() method (you can pass a null).
Try this:
Object getFieldValue(String path) throws Exception {
int lastDot = path.lastIndexOf(".");
String className = path.substring(0, lastDot);
String fieldName = path.substring(lastDot + 1);
Class myClass = Class.forName(className);
Field myField = myClass.getDeclaredField(fieldName);
return myField.get(null);
}

Related

Java constructor use parameter to create new list

New to Java. I'm trying to create a class to convert to JSON string to send as POST request using GSON. This class was created within a public class Called BertClient:
private class BertJsonRequest {
private Integer id;
private List<String> texts;
public BertJsonRequest(int x, String text) {
this.id = x;
this.texts = new ArrayList<>();
this.texts.add(text);
}
}
How I use that:
BertJsonRequest rawRequestBody = new BertJsonRequest(1, text);
Gson gsonToJson = new Gson();
String requestBody = gsonToJson.toJson(rawRequestBody);
For the line where I'm creating new BertJsonRequest My IDE tells me that BertClient.this cannot be referenced from a static content.
I wonder what that means.
Am I building the constructor correctly?
I think I'm not. I just want to be able to pass in a String so that constructor can create a List of String using that String.
Your class access modifier is set to private. Try setting the access modifier to public instead.
public class BertJsonRequest {
private Integer id;
private List<String> texts = new ArrayList<>();
public BertJsonRequest(int x, String text) {
id = x;
texts.add(text);
}
}
What I understood by reading your comments on other's answers was, that your BertClientRequest probably is an inner class.
In case it really is an inner class, and you try to call it in a static method of your containing class, it becomes apparent that you cannot instantiate your inner class as that inner class is not static.
public class BertClient {
private class BertClientRequest {
/* some code */
}
static void aStaticMethod() {
// ...
// Inner class BertClientRequest is unknown to your static method as it is not static,
// thus giving you a compile time error
BertClientRequest rawRequest = new BertClientRequest(1, text);
// ...
}
}
The fix would be in this case to change your inner class to static:
private static class BertClientRequest
I guess your BertJsonRequest is a inner class of BertClient. You can't instantiate BertJsonRequest outside of BertClient. You can make BertJsonRequest class static for this to work.

Is there any way to generate code in Interface on implementing it in a class

I want to add all the abstracts of getter and setter of a class to the interface that I am implementing in that particular interface. I also want to generate a final variable that resembles class variable. This variable can be used as string to access class variable after deserializing.
Eg:
public class Abc implements IAbc{
private String oneVariable;
public String getOneVariable(){
return oneVariable;
}
}
On implementing the above class with interface IAbc. IAbc should contain the following code:
public interface IAbc{
public static final String ONE_VARIABLE = "oneVariable";
public getOneVariable();
}
I have tried googling for the solution but could not get any. Also the methods in class should have the annotation #Override after this code is generated.
TL;DR This is an interesting programming challenge, but I find very little use for this in real life scenarios.
Here the name of the first string variable is known before hand, you can directly store the final value in this instead of the round-about way of storing the name of second variable.
If understand correctly you are trying to access a (String) variable of a class whose name will be in another string variable. This is possible using java reflection.
Additionally you want this code to be placed in an interface such that it can be (re)used in all the classes implementing it.
import java.lang.reflect.Field;
interface Foo {
public default String getStringVar()
throws NoSuchFieldException, IllegalAccessException {
// get varName
Class thisCls = this.getClass();
Field varNameField = thisCls.getField("varName");
String varName = (String) varNameField.get(this);
// get String variable of name `varName`
Field strField = thisCls.getField(varName);
String value = (String) strField.get(this);
return value;
}
}
class FooImpl1 implements Foo {
public final String varName = "str1";
public String str1 = "some value";
}
class FooImpl2 implements Foo {
public final String varName = "str2";
public String str2 = "some other value";
}
class Main {
public static void main(String[] args)
throws NoSuchFieldException, IllegalAccessException {
System.out.println(new FooImpl1().getStringVar());
System.out.println(new FooImpl2().getStringVar());
}
}
Here I have two String members in classes implementing interface Foo. The first varName contains the variable name of the second String, second String variable contains the data.
In the interface using reflection I am first extracting the variable name stored in varName, then using this extracting the value of second String.

How to get private inner class instance with reflection in Java?

public class OuterClass {
private static class InnerClass {
public int id = 0;
}
private static InnerClass[] innerArr;
}
Need to get innerArr value with reflection in Java.
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class<?> cla = loader.loadClass("OuterClass");
Field innerArrRef = cla.getDeclaredField("innerArr");
innerArrRef.setAccessible(true);
OuterClass.InnerClass[] innerArrValue = (OuterClass.InnerClass[])innerArrRef.get(cla);
Above code doesn't work for InnerClass is a private class.
Let's adjust your OuterClass code a bit to make it more interesting: put in instance of InnerClass in the array:
private static InnerClass[] innerArr = { new InnerClass() };
Now you can't directly refer to the private type InnerClass in another class that is trying to get the static field using reflection. You can first refer to it as an array of Object.
public static void main(String[] args) throws Exception {
Class<?> cla = OuterClass.class;
Field innerArrRef = cla.getDeclaredField("innerArr");
innerArrRef.setAccessible(true);
Object[] innerArrValue = (Object[]) innerArrRef.get(cla);
You'll need to use reflection and the Class object to use the InnerClas type.
One way is to use the declaredClasses property of the OuterClass' class object:
Class<?> inner = cla.getDeclaredClasses()[0];
But if there's more than one member class, you need to loop through the array and search for the right one. Another way is to use the knowledge that javac will give your InnerClass a fully-qualified type name that looks like mypackage.OuterClass$InnerClass:
Class<?> inner = cla.getClassLoader().loadClass(cla.getName() + "$InnerClass");
Once you have the class object of the InnerClass, you can use reflection to access its field and methods:
Field id = inner.getField("id");
System.out.println("Inner id: " + id.getInt(innerArrValue[0]));
}

with StringBuffer how to achieve 100% immutability.. i want to do it with stringbuffer only. no other datatype

Consider following code
final class immudemo
{
private static final StringBuffer bf = new StringBuffer("Yaxita");
public StringBuffer getter()
{
return bf;
}
}
public class HelloWorld{
public static void main (String args[])
{
immudemo obj1 = new immudemo();
StringBuffer bf2 = obj1.getter();
bf2.append("Shah");
System.out.println(obj1);
}
}
in above code even though StringBuffer declared as final i am able to change it. Can anyone please help me how to achieve 100% immutability ?
P.S. : I want to achieve this with StringBuffer only. If you provide anything please check it should be related to StringBuffer only.
YaxitaShah , in this case , StringBuffer declared as final , but StringBuffer references are passed through the getter method in the immudemo class;
may be you can:
final class immudemo
{
private static final StringBuffer bf = new StringBuffer("Yaxita");
public StringBuffer getter(){
return new StringBuffer(bf);
}
public String toString() {
return bf.toString();
}
}
public class HelloWorld{
public static void main (String args[])
{
immudemo obj1 = new immudemo();
StringBuffer bf2 = obj1.getter();
bf2.append("Shah");
System.out.println(obj1);
}
}
With final you define, that you cannot set another object to "bf".
The status of the object itself still can be changed if it is mutable.
That is the case for StringBuffer. And because you release it to the outside by "getter", your class "immudemo" is also mutable.
If you use String as return type for "getter", you would have an immutable object on the outside, but a mutable on the inside.
(Your class "immudemo" does not need to be final for immutability of its instances.)
Therefore your class "immudemo" would be immutable, if you return the type String instead of StringBuffer by your method "getter".
class immudemo
{
private static final StringBuffer bf = new StringBuffer("Yaxita");
public String getter(){
return bf.toString();
}
}
public class HelloWorld{
public static void main (String args[])
{
immudemo obj1 = new immudemo();
String bf2 = obj1.getter();
bf2.append("Shah"); // does not work anymore
System.out.println(obj1);
}
}
Additional: Follow this strategy to define immutable objects yourself: https://docs.oracle.com/javase/tutorial/essential/concurrency/imstrat.html
in above code even though StringBuffer declared as final i am able to
change it.
No, append() is not creating new object of your Stringbuffer, it just modifying the value of the same referenced object.
See the java doc of final variable which says,
Once a final variable has been assigned, it always contains the same
value. If a final variable holds a reference to an object, then the
state of the object may be changed by operations on the object, but
the variable will always refer to the same object.
So, Immutable class can be by,
Declare the class as final so it can’t be extended.
Make all fields private so that direct access is not allowed.
Don’t provide setter methods for variables
Make all mutable fields final so that it’s value can be assigned only once.
Initialize all the fields via a constructor performing deep copy.
Perform cloning of objects in the getter methods to return a copy rather than - returning the actual object reference.
To make the StringBuilder class as Immutable check the below class, testSB instance variable, define the return type of the getter method as StringBuilder but maintain internally as String objects...
public class ImmutableClass {
private final int value;
private final String name;
private final StringBuilder name1;
private final String testSB;
// changed the constructor, to say Immutable, instead of mutable
public ImmutableClass( int aValue, String aName, StringBuilder aName1,StringBuilder aTestSB) {
// The value is set. Now, and forever.
value = aValue;
name1=aName1;
name=aName;
testSB=new String(aTestSB);
}
public StringBuilder getTestSB() {
return new StringBuilder(testSB);
}
public String getName() {
return name;
}
public StringBuilder getName1() {
return name1;
}
public final int getValue() {
return value;
}
}

Reflection: Constant variables within a class loaded via reflection

I have a class which has a bunch of Constant Strings.
I need to load this class via reflection and retrieve those constants.
I can get up to:
controllerClass = Class.forName(constantsClassName);
Object someclass = controllerClass.newInstance();
but I am confused on how to retrieve the fields in this class.
A quick sample on accessing fields --
Field[] fields = controllerClass.getDeclaredFields();
for ( Field field : fields ) {
field.setAccessible(true);
System.out.println(field.get(someClass));
}
Here's a little sample:
import java.lang.reflect.Field;
public class Test {
public static class X {
public static int Y = 1;
private static int Z = 2;
public int x = 3;
private int y = 4;
}
public static Object getXField(String name, X object) {
try {
Field f = X.class.getDeclaredField(name);
f.setAccessible(true);
return f.get(object);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) {
System.out.println(Test.getXField("Y", null));
System.out.println(Test.getXField("Z", null));
System.out.println(Test.getXField("x", new X()));
System.out.println(Test.getXField("y", new X()));
}
}
Running this little program outputs:
1
2
3
4
A few observations:
For static fields the supplied object to Field.get() can be null.
For brevity, I used an exception catch-all with the base Exception class - you should use explicit exception classes in your code.
While Field.get() usually works as expected, the same cannot be said for Field.set() and its friends. More specifically it will happily change the value of a constant (e.g. a final field, or a private field that is never modified in the class methods), but due to constant inlining the old value may remain in use.
Assuming these constants are in static fields:
import java.lang.reflect.*;
public class Reflect {
public static final String CONSTANT_1 = "1";
public static final String CONSTANT_2 = "2";
public static final String CONSTANT_3 = "3";
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("Reflect");
Field[] fields = clazz.getDeclaredFields();
for(Field f: fields) {
// for fields that are not visible (e.g. private)
f.setAccessible(true);
// note: get(null) for static field
System.err.printf("%s: %s\n",f, (String)f.get(null) );
}
}
}
The output is:
$ java Reflect
public static final java.lang.String Reflect.CONSTANT_1: 1
public static final java.lang.String Reflect.CONSTANT_2: 2
public static final java.lang.String Reflect.CONSTANT_3: 3
Note that to get the value of a static field, you supply null as the arg.
You get to know about the modifiers via the class and not the object reference.
http://download.oracle.com/javase/tutorial/reflect/class/classModifiers.html

Categories