I have an activity with some final variables. I extracted their values (let's assume they're all Strings) into a resources file.
The problem:
If I directly assign them on the instantiation (as following):
private final String PREFERENCE_NAME = getResources().getString(R.string.preference_name);
I get the following error:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()' on a null object reference
I understand the problem; the onCreate() method has not been called yet which means I cannot access context-related methods (getResources()).
If I want to assign the value in the onCreate() method of the activity, I get the error Cannot assign value to final variable 'PREFERENCE_NAME'
The question is: How can I get my final variables to be assigned from the resources file? And if this is not possible, what is the best practice for a solution?
Thanks in advance.
The simple answer is that you can't.
Variables declared final can only be set when the object is instantiated (i.e. in the constructor or with initialiser code).
Either use getResources().getString(R.string.preference_name); all the time or use a non-final variable.
The complex answer is that you can but that you shouldn't.
When you declare a variable final the compiler and VM uses this to make optimisations and assumptions. It can do this because the variable is guaranteed to never change. Changing it after it has been initialised can cause really weird bugs so you absolutely should not do that.
Here's how you do it:
public class FinalMessage {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
FinalMessage f = new FinalMessage("Hello World!");
System.out.println(f.getMessage());
f.changeFinalMessage("Hello Mars!");
System.out.println(f.getMessage());
}
private final String message;
public FinalMessage(String message) {
this.message = message;
}
void changeFinalMessage(String newMessage) throws IllegalAccessException, NoSuchFieldException {
final Field field = FinalMessage.class.getDeclaredField("message");
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(this, newMessage);
}
String getMessage() {
return message;
}
}
This will output:
Hello World!
Hello Mars!
Great, so we changed a final variable. No problem right?
Well, take this example instead:
public class FinalMessage {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
FinalMessage f = new FinalMessage();
System.out.println(f.getMessage());
f.changeFinalMessage("Hello Mars!");
System.out.println(f.getMessage());
}
private final String message = "Hello World!";
void changeFinalMessage(String newMessage) throws IllegalAccessException, NoSuchFieldException {
final Field field = FinalMessage.class.getDeclaredField("message");
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(this, newMessage);
}
String getMessage() {
return message;
}
}
This will output:
Hello World!
Hello World!
Wait, what?
The problem is that the compiler can see that the variable message is always going to be "Hello World!" so it inlines "Hello World!" instead of our call to f.getMessage(). If you run this in a debugger you will see the debugger reflect the updated message in the instance to "Hello Mars!" but since the variable is actually never accessed it won't affect the outcome of the program.
So to summarize: You can update final fields via reflection (granted that there is no Security Manager present that prevents you from doing it), but you should not do it since it can have very, very weird side-effects.
I am not responsible if your house gets termites or your cat catches on fire if you actually decide to implement this.
In this case I think the best thing to do it just make multiple calls to the resources. You still only have to change the value in one place and the call to getResources() isn't an expensive one.
Use your application context:
Create an application class:
public class MyApplication extends Application {
private static Context mContext;
#Override
public void onCreate() {
super.onCreate();
mContext = getApplicationContext();
}
public static String getStr(int resId) {
return mContext.getString(resId);
}
}
Use it in your manifest:
<application
android:name=".MyApplication"
...
Call it anywhere in your application:
static final String NAME = MyApplication.getStr(R.string.app_name);
You can use a factory pattern to solve this issue.
The builder is a class that aggregates the data needed to create your object, and when you are done - you just build your class.
In this approach, the data needed to generate the object is also available to the factory, and he can easily create the object, and initialize the final field when invoking its constructor.
You will have something like
class MyFactory {
private Resource getResources() { ... }
public MyObject build() {
String perference_name = getResources().getString(R.string.preference_name);
/...
return new MyObject(perfence_name ,....);
}
}
You can simply declare it as a final method:
private final String PREFERENCE_NAME() {
return getResources().getString(R.string.preference_name);}
Related
I would like to have a static map where the values are instance methods. Someting like:
public class MyClass {
static Map<MyEnum, Consumer<String>> methodMapping;
static {
methodMapping = new EnumMap<>(MyEnum.class);
methodMapping.put(MyEnum.FIRST, MyClass::firstMethod);
methodMapping.put(MyEnum.SECOND, MyClass::secondMethod);
}
void firstMethod(String param) {
...
}
void secondMethod(String param) {
...
}
}
This gives me an error saying "Non-static method cannot be referenced from a static context". I understand why this would be a problem if I would try to call the methods from the static context, but isn't it possible from an instance method to retrieve the method from the map and pass it this? Like:
MyClass.methodMapping.get(MyEnum.FIRST).accept(this, "string");
This is solvable as easy as changing Consumer to BiConsumer, turning the receiver instance of MyClass to a parameter of the function:
public class MyClass {
static Map<MyEnum, BiConsumer<MyClass,String>> methodMapping;
static {
methodMapping = new EnumMap<>(MyEnum.class);
methodMapping.put(MyEnum.FIRST, MyClass::firstMethod);
methodMapping.put(MyEnum.SECOND, MyClass::secondMethod);
}
void firstMethod(String param) {
...
}
void secondMethod(String param) {
...
}
void callTheMethod(MyEnum e, String s) {
methodMapping.get(e).accept(this, s);
}
}
You initialize methodMapping in a static initialization block. At that point, your instance methods can't be referred to yet because you haven't called new MyClass() yet.
You could fix this by either making your methods static, or moving the methodMapping initialization from the static block to a constructor.
PS: The keyword static can be omitted from the initialization block
isn't it possible from an instance method to retrieve the method from the map and pass it this
No. A Consumer only has a single parameter accept() method, so there's no such thing as "passing this at calling time".
You need an instance when creating the method reference, so this questions boils down to "can't call instance method from a static context".
It seems that you don't understand that
static Map<MyEnum, Consumer<String>> methodMapping;
static {
does exactly that, trying to call the methods from the static context where they don't exist.
The key thing to understand here: you intend to create a method reference; and a method reference needs some object to invoke that method on. Thus there is no "delaying"; there is no way in java to express "wait for this to be meaningful"; or in other words: there is no way in a static context to express: "you will be used in a non-static context later on; and then pick the corresponding this from there".
The key is to defer the specification of this or to be more specific: The particular instance on which a method is to be called. So instead of storing method references directly we store functions that accept an instance and return a method reference for that instance.
MyClass.java
public class MyClass {
static Map<MyEnum, Function<MyClass, Consumer<String>>> methodMapping;
static {
methodMapping = new EnumMap<>(MyEnum.class);
methodMapping.put(MyEnum.FIRST, t -> t::firstMethod);
methodMapping.put(MyEnum.SECOND, t -> t::secondMethod);
}
private String id;
public MyClass(String id) {
this.id = id;
}
void firstMethod(String param) {
System.out.println(id + ", 1st method, " + param);
}
void secondMethod(String param) {
System.out.println(id + ", 2nd method, " + param);
}
void dispatchMethod(MyEnum myEnum, String param) {
methodMapping.get(myEnum).apply(this).accept(param);
}
}
Main.java
public class Main {
public static void main(String[] args) {
MyClass instance = new MyClass("MyInstance");
MyClass.methodMapping.get(MyEnum.FIRST).apply(instance).accept("Using mapping directly");
instance.dispatchMethod(MyEnum.SECOND, "Using dispatch method");
}
}
Ideally methodMapping should be shielded against direct access from other classes so I'd suggest taking the dispatchMethod approach and making methodMapping private and immutable.
I am doing my project in university using java, I have got stuck to assign value to variable. In my class I have few fields without values. However, I want to provide value to variable reading from database each time when class constructor is called. Now, there are 7 fields in my class for example and from that there will be use of only one field based on execution, now I want to assign value to that field(s) at run time. Means, if there is only two field which will be used then I want to assign value to only those two fields. I will get the field name from database with value, so I will check if the field name is matching then I will assign the value to variable. OR if there is any other value to handle this.
Below given code is not working, syntax error
I would appreciate your inputs.
package RandD;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
public class Reflection {
public static final String field1="";
static final int field2=0;
private final String field3="";
static String field4="";
protected String field5="";
List<String> element1;
HashMap<String, Integer> element2;
public Reflection() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException{
test();
}
public static void main(String arg[]) throws NoSuchFieldException, SecurityException{
new Reflection().test();
}
public void test() throws NoSuchFieldException, SecurityException{
Field[] field = Reflection.class.getDeclaredFields();
for(Field fd:field){
if(fd.getName().equalsIgnoreCase("field3")){
fd.getName()="Hello World";
}
}
}
}
Eventhough you can access and modify private variables through reflection, use it sparingly.
Sample code to set private fields.
import java.lang.reflect.*;
public class ReflectionDemo{
public static void main(String args[]){
try{
Field[] fields = A.class.getDeclaredFields();
A a = new A();
for ( Field field:fields ) {
field.setAccessible(true);
if(field.getName().equalsIgnoreCase("name")){
field.set(a, "StackOverFlow");
System.out.println("A.name="+field.get(a));
}
if(field.getName().equalsIgnoreCase("age")){
field.set(a, 20);
System.out.println("A.age="+field.get(a));
}
if(field.getName().equalsIgnoreCase("rep")){
field.set(a,"New Reputation");
System.out.println("A.rep="+field.get(a));
}
if(field.getName().equalsIgnoreCase("count")){
field.set(a,25);
System.out.println("A.count="+field.get(a));
}
}
}catch(Exception err){
err.printStackTrace();
}
}
}
class A {
private String name;
private int age;
private final String rep;
private static int count=0;
public A(){
name = "Unset";
age = 0;
rep = "Reputation";
count++;
}
}
output:
java ReflectionDemo
A.name=StackOverFlow
A.age=20
A.rep=New Reputation
A.count=25
Your syntax error comes from the line:
fd.getName()="Hello World";
Replace it with
fd.set(this, "Hello World");
The result of getName() is a string constant. You cannot assign something to a string constant.
You need two things: the instance that the field is to be set on, and the value to be set.
Your code, however, is trying to set the value of a final field, which, although with the code below will compile, will still fail at runtime as you cannot modify a final field.
But here how:
//First, have at hand the instance on which to set the value:
Reflection reflection = new reflection();
for(Field fd:field){
if(fd.getName().equalsIgnoreCase("field3")){
fd.setAccessible(true);
fd.set(reflection, "Hello World");
}
}
As mentioned above, you should expect a runtime exception as "field3" is final.
If the target field is static, such as field1, you could pass null to the first parameter:
for(Field fd:field){
if(fd.getName().equalsIgnoreCase("field1")){
fd.setAccessible(true);
fd.set(null, "Hello World");
}
}
As a side note, instead of looping and matching on a hard-coded name, you could simply get the field by name:
Field field1 = Reflection.class.getDeclaredField("field1");
field1.setAccessible(true);
field1..set(null, "Hello World");
I have following code:
public class LoadProperty
{
public static final String property_file_location = System.getProperty("app.vmargs.propertyfile");
public static final String application-startup_mode = System.getProperty("app.vmargs.startupmode");
}
It reads from 'VM arguments' and assigns to variables.
Since static final variable is only initialized at class load,
how can I catch exception in case some one forgets to pass parameter.
As of now, when I am using 'property_file_location' variable, exception is encountered in following cases:
If value is present, and location is wrong, FileNotFound exception comes.
If it is not initialized properly(value is null), it throws NullPointerException.
I need to handle second case at time of initialization only.
Similiar is case of second variable.
Whole idea is
To initialize application configuration parameters.
If successfully initialized, continue.
If not, alert user and terminate application.
You can catch it this way:
public class LoadProperty
{
public static final String property_file_location;
static {
String myTempValue = MY_DEFAULT_VALUE;
try {
myTempValue = System.getProperty("app.vmargs.propertyfile");
} catch(Exception e) {
myTempValue = MY_DEFAULT_VALUE;
}
property_file_location = myTempValue;
}
}
You can use a static initializer block as suggested by the rest of the answers. Even better move this functionality to a static utility class so you can still use them as an one-liner. You could then even provide default values e.g.
// PropertyUtils is a new class that you implement
// DEFAULT_FILE_LOCATION could e.g. out.log in current folder
public static final String property_file_location = PropertyUtils.getProperty("app.vmargs.propertyfile", DEFAULT_FILE_LOCATION);
However if those properties are not expected to exist all the time, I would suggest to not initialize them as static variables but read them during normal execution.
// in the place where you will first need the file location
String fileLocation = PropertyUtils.getProperty("app.vmargs.propertyfile");
if (fileLocation == null) {
// handle the error here
}
You may want to use a static bloc :
public static final property_file_location;
static {
try {
property_file_location = System.getProperty("app.vmargs.propertyfile");
} catch (xxx){//...}
}
I am very new in Reflection and I have a doubt like:
public void setAccessible(boolean flag) throws SecurityException
This method has a boolen parameter flag, which indicates the new accessibility of any fields or methods.
For an example if we are try to access a private method of a class from outside the class then we fetch the method using getDeclaredMethod and set the accessibility as true, so it can be invoked, like: method.setAccessible(true);
Now in which scenario we should use method.setAccessible(false); , for an example it can be used when there is a public method and we set the accessibility as false. But what is the need of that? Is my understanding clear?
If there is no use of method.setAccessible(false) then we can change the method signature like:
public void setAccessible() throws SecurityException
Probably you would never do setAccessible(false) in your entire life. This is because setAccessible doesn't the change the visiblity of the a member permanently. When you to something like method.setAccessible(true) you are allowed to make subsequent calls on this method instance even if the method in the original source is private.
For example consider this:
A.java
*******
public class A
{
private void fun(){
....
}
}
B.java
***********
public class B{
public void someMeth(){
Class clz = A.class;
String funMethod = "fun";
Method method = clz.getDeclaredMethod(funMethod);
method.setAccessible(true);
method.invoke(); //You can do this, perfectly legal;
/** but you cannot do this(below), because fun method's visibilty has been
turned on public only for the method instance obtained above **/
new A().fun(); //wrong, compilation error
/**now you may want to re-switch the visibility to of fun() on method
instance to private so you can use the below line**/
method.setAccessible(false);
/** but doing so doesn't make much effect **/
}
}
Scenario: you removed protection from a private field with Field.setAccessible(true), read it and returned the field into original state with Field.setAccessible(false).
//create class PrivateVarTest { private abc =5; and private getA() {sop()}}
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class PrivateVariableAcc {
public static void main(String[] args) throws Exception {
PrivateVarTest myClass = new PrivateVarTest();
Field field1 = myClass.getClass().getDeclaredField("a");
field1.setAccessible(true);
System.out.println("This is access the private field-"
+ field1.get(myClass));
Method mm = myClass.getClass().getDeclaredMethod("getA");
mm.setAccessible(true);
System.out.println("This is calling the private method-"
+ mm.invoke(myClass, null));
}
}
When I debug through Java code, I often see lot of properties of object that are useful to me in my application to get them and do something with them but I look at the API or javadocs, the class does not have any such properties or getter methods to get these property values. For example:
myPhoneCallObj.foo has value "bar" in debugger
myPhoneCallObj.baz has value otherObj which in turn has other values like otherObj.baz
I cannot do in Java:
String myValue = myPhoneCallObj.foo
as it would not compile in Java but in Groovy I can write above code and during runtime, it gets the value I need. How the same can be done in Java code?
myPhoneCallObj is an instance of Java Interface PhoneCall and the debugger was showing this as of type PhoneCallImpl ( third party implementation of the interface). I do not have access to source code of that third party to look into to understand but the Interface has complete documentation and Javadoc for the APIs.
Given a class like:
class X
{
private int value;
#Override
public String toString()
{
return (Integer.toString(value));
}
}
You can do this:
import java.lang.reflect.Field;
public class Test
{
public static void main(final String[] argv)
throws NoSuchFieldException,
IllegalArgumentException,
IllegalAccessException
{
final X x;
x = new X();
System.out.println(x);
changeValue(x);
System.out.println(x);
}
private static void changeValue(final X x)
throws NoSuchFieldException,
IllegalArgumentException,
IllegalAccessException
{
final Class<X> clazz;
final Field field;
clazz = X.class;
field = clazz.getDeclaredField("value");
field.setAccessible(true);
field.set(x, Integer.MAX_VALUE);
}
}
The key here is the call to field.setAccessible(true); which says that even though value is private allow it to be accessed.
However there is typically a reason why a field is private, and you should not be surprised if your code breaks with a later release of the 3rd party code that you are manipulating.
Are these properties private or protected in scope? The only properties that you will be able to directly access are public properties, but all variables will show up in a debug object inspector.
If you absolutely need to get the value, you can use reflection. (Which is likely what Groovy is doing)