Reflectively accessing a static variable in a Java class - java

I've been given no other choice but to access a set of classes, which I cannot modify, with this structure through reflection.
Using the method shown in the main method below however, throws a NullPointerException. The null pointer being "table" in the constructor when f1.get(null) is called.
I am unable to instantiate the classes beforehand because the only constructor is the one shown, which is private. So there is no way for me to explicitly set table either.
Anyone know of a way for me to reflectively call Legacy.A?
public class Legacy {
public static final Legacy A = new Legacy("A");
public static final Legacy B = new Legacy("B");
private String type0;
private static Map<String, Legacy> table = new HashMap<String, Legacy>();
private Legacy(String id) {
type0 = id;
table.put(type0, this);
}
public static void main(String[] args) throws Exception {
Field f1 = Legacy.class.getDeclaredField("A");
Object o = f1.get(null);
}
}
In before "Reflection == BAD!!!"

The order of the static initializers is wrong, table must come before the constructor calls.
This is the reason that you get the exception when the class is loaded and initialized. This has nothing to do with reflection.

Since this is confusing, I would write it like this:
public class Legacy {
static {
table = new HashMap<String, Legacy>();
A = new Legacy("A");
B = new Legacy("B");
}
public static final Legacy A;
public static final Legacy B;
private String type0;
private static Map<String, Legacy> table;
private Legacy(String id) {
type0 = id;
table.put(type0, this);
}
public static void main(String[] args) throws Exception {
Field f1 = Legacy.class.getDeclaredField("A");
Object o = f1.get(null);
}
}
This way, even if the members change location (due to refactoring, line alignment or whatever) the code will always work.

I tried this, because I couldn't see what was wrong with your example. It worked if I reordered the declarations:
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class Legacy {
private String type0;
private static Map< String, Legacy > table = new HashMap< String, Legacy >();
private Legacy( String id ) {
type0 = id;
table.put( type0, this );
}
public static final Legacy A = new Legacy( "A" );
public static final Legacy B = new Legacy( "B" );
public static void main( String[] args ) throws Exception {
Field f1 = Legacy.class.getDeclaredField( "A" );
Object o = f1.get( null );
}
}
The static declarations need the (preceding) constructor.

Related

Creating multiple objects using the same instance

I just saw this tutorial creating multiple objects using the same instance by applying the DAO pattern and tried it in a simple console, but I always get this message java.lang.NullPointerException I'm now confused, as far as I know, a constructor can be used once only, and the object will be immutable. Kindly look at this:
Fighter.java
public class Fighter {
private String style;
public Fighter() {}
public String getStyle() {
return style;
}
public void setStyle(String style) {
this.style = style;
}
}
FightersDAO.java
public class FightersDAO {
public List<Fighter> getFighters(){
List <Fighter> fighter = new ArrayList<>();
String [] styles= { "Karate", "Sumo", "Pro-Wrestling" };
for(int i=0; i < styles.length; i++) {
Fighter temp = new Fighter();;
temp.setStyle(styles[i]);
fighter.add(temp);
}
return fighter;
}
}
Demo.java
public class Demo {
private static FightersDAO fighterDAO;
public static void main (String [] args) {
List <Fighter> fighters = fighterDAO.getFighters();
for(Fighter e: fighters) {
System.out.println(e.getStyle()); //this should output the objects, but nothing shows
}
}
}
Why is it null? What part did went wrong
The variable fighterDAO is never initialized. Therefore you get a NPE here:
List <Fighter> fighters = fighterDAO.getFighters();
To fix that use:
private static FightersDAO fighterDAO = new FightersDAO();
private static FightersDAO fighterDAO;
I think there is a problem because it is not initialized.
Change it:
private static FightersDAO fighterDAO = new FightersDAO();
In your code
private static FightersDAO fighterDAO;// here is not initialized. its just a declaration so fighterDAO = null;
while executing below code will throw exeption
List fighters = fighterDAO.getFighters();// means null.getFighters();
Below is the correct code
package aks;
import java.util.List;
public class Demo {
private static FightersDAO fighterDAO= new FightersDAO();
public static void main (String [] args) {
List <Fighter> fighters = fighterDAO.getFighters();
for(Fighter e: fighters) {
System.out.println(e.getStyle());
}
}
}
You can analyse this by just debuggin on eclise or any IDE
If you want same instance use below code
private static FightersDAO fighterDAO = new FightersDAO();

Using an argument as an interface item

In the program I am making, I am trying to get a formatted season name for a given season(formatted so it . I keep the formatted names in an interface, since if I were to use a map, it would be unnecessarily regenerated, since I don't make an instance of TeamBuilder
The Seasons interface:
public interface Seasons {
/*
* Contains a formatted list of seasons.
*
* An interface is being used as an alternative to using a Map in the
* TeamBuilder class, since calling parseTeam would have to build
* mappings for the seasons each time it
* was called. This way, the formatted name can simply be grabbed
*/
final String Skyrise = "Skyrise";
final String Toss_Up = "Toss%20Up";
final String Sack_Attack = "Sack%20Attack";
final String GateWay = "Gateway";
final String Round_Up = "Round%20Up";
final String Clean_Sweep = "Clean%20Sweep";
final String Elevation = "Elevation";
final String Bridge_Battle = "Bridge%20Battle";
final String Nothing_But_Net = "Nothing%20But%20Net";
final String Starstruck = "Starstruck";
final String In_The_Zone = "In%20The%20Zone";
final String Turning_Point = "Turning%20Point";
}
The problem comes when I try to grab these seasons. My TeamBuilder class takes in an argument(String season), which is unformatted. My question is, is there any way that I can use a String argument for a method to get a specific item from an interface? This is the most preferable to using a HashMap, which would needlessly regenerate the same information
All these classes can be found on the Github page for this project.
If you want to do it in a typed way, you can use Enum for this:
enum Season{
Skyrise,Toss_Up, Sack_Attack;
#Override
public String toString() {
switch(this){
case Skyrise: return "Skyrise";
case Toss_Up: return "Toss%20Up";
case Sack_Attack: return "Sack_Attack";
default: return "";
}
}
}
public class main{
public static void printSeason(Seasons seasons){
System.out.println(seasons);
}
public static void main(String[] args) {
Seasons e = Seasons.Skyrise;
printSeason(e);
System.out.println(e);
}
}
Since the compiler internally invokes the toString(), you can pass the argument as a Seasons or a String like my example.
And if you still want to use a map without "unnecessarily regenerated" you can use a static field with static initializer like this:
class Seasons {
private static Map<String,String> map = new HashMap<>();
static {
map.put("Skyrise", "Skyrise");
map.put("Toss_Up", "Toss%20Up");
}
public static String getFormatted(String key){
return map.getOrDefault(key,"");
}
}
class main{
public static void main(String[] args) {
System.out.println(Seasons.getFormatted("Skyrise"));
}
}
Just to integrate on Snoob answer you can have enum with fields, so:
enum Season
{
Skyrise("Skyrise"),
Toss_Up("Toss%20Up"),
Sack_Attack("Sack%20Attack")
;
public final String fancyName;
private Season(String fancyName)
{
this.fancyName = fancyName;
}
}
You really have all the benefits without any drawback.

Updating a static final field from an instance initializer

Java prohibits access of a final static field from an initializer. For example:
public enum Example {
ValueA("valueAA", "valueAB"),
ValueB("valueBA", "valueBB");
final static Map<String, Example> exampleByPropertyA = new HashMap<>();
final String propertyA;
final String propertyB;
Example(String propertyA, String propertyB) {
this.propertyA = propertyA;
this.propertyB = propertyB;
Example.exampleByPropertyA.put(propertyA, this); // <- Not permitted
}
}
However, if the update to the static Map is performed in a separate method that is called by the initializer, this is fine. For example:
public enum Example {
ValueA("valueAA", "valueAB"),
ValueB("valueBA", "valueBB");
final static Map<String, Example> exampleByPropertyA = new HashMap<>();
final String propertyA;
final String propertyB;
Example(String propertyA, String propertyB) {
this.propertyA = propertyA;
this.propertyB = propertyB;
addExample(this);
}
private addExample(Example example) {
Example.exampleByPropertyA.put(example.propertyA, example); // <- Permitted
}
}
Given this context, my question is: Does a call to a member method constitute a "freeze action" or is it indicative to the JVM that the object is, for all intents and purposes, "initialized"? Curious why this makes a difference.
I've done some searching, but haven't found anything that articulates this well.
Thank you in advance!
Does a call to a member method constitute a "freeze action" or is it indicative to the JVM that the object is, for all intents and purposes, "initialized"? Curious why this makes a difference.
The problem is that your class is initialised top to bottom. This means your static fields have not been initialised yet i.e. your Map is null.
Another approach is to add a static initialisation block to be called after everything has been initialised.
static {
for (Example e: values()) {
addExample(e);
}
}
private static addExample(Example example) {
Example prev = exampleByPropertyA.put(example.propertyA, example);
assert prev == null;
}
NOTE: You can see a final variable before it is initialised. This means final can have a before and after value even without using reflection.
public class A {
final String text = getText();
private String getText() {
System.out.println("text= " + text);
return "is set";
}
public static void main(String... args) {
new A().getText();
}
}
prints
text= null
text= is set
Using reflection you can alter final fields even after initialisation though you should avoid doing this unless there is no other option.
The correct way to do what you're trying to do, is to write a static initializer, which runs after all the enums have been created.
Defensive programming: You should also add a simple check to guard against programming errors.
public enum Example {
ValueA("valueAA", "valueAB"),
ValueB("valueBA", "valueBB");
final static Map<String, Example> exampleByPropertyA = new HashMap<>();
static {
for (Example ex : values())
if (exampleByPropertyA.put(ex.propertyA, ex) != null)
throw new IllegalStateException("Duplicate propertyA: " + ex.propertyA);
}
final String propertyA;
final String propertyB;
Example(String propertyA, String propertyB) {
this.propertyA = propertyA;
this.propertyB = propertyB;
}
}

Return a string value to the pass-in varibale from the argument in a function

I want the pass-in variable "aaa" to be returned the value from the argument of the function. I really need my argument in the function to be defined as String, and want whatever change of the argument in the function to be return to the pass-in variable.
How do I make this happen in Java? If anyone could help I will appreciate!
public class DeppDemo {
private String aaa;
public void abc(String aaa) {
aaa = "123";
}
public static void main(String[] args) {
DeppDemo demo = new DeppDemo();
demo.abc(demo.aaa);
System.out.println(demo.aaa);
}
}
You cannot do it like this: String class in Java is immutable, and all parameters, including object references, are passed by value.
You can achieve the desired result in one of three ways:
Return a new String from a method and re-assign it in the caller,
Pass mutable StringBuilder instead of a String, and modify its content in place, or
Pass an instance of DeppDemo, and add a setter for aaa.
Here are some examples:
public class DeppDemo {
private String aaa;
private StringBuilder bbb = new StringBuilder();
public String abc() {
return "123";
}
public void def(StringBuilder x) {
x.setLength(0);
x.append("123");
}
public static void main(String[] args) {
DeppDemo demo = new DeppDemo();
demo.aaa = demo.abc(); // Assign
demo.def(demo.bbb); // Mutate
System.out.println(demo.aaa);
}
}
It's really unclear what you're asking, but it sounds like you're trying to change the content of a variable passed into a function. If so, you can't in Java. Java doesn't do pass-by-reference.
Instead, you pass in an object or array, and modify the state of that object or array.
public class DeppDemo {
public void abc(String[] aaa) {
aaa[0] = "123";
}
public static void main(String[] args) {
String[] target = new String[1];
DeppDemo demo = new DeppDemo();
demo.abc(target);
System.out.println(target[0]);
}
}
But if you're asking how to update the aaa field using the aaa argument, then you need to qualify your reference to the field using this., since you've used the same name for both. Or change the name of the argument.
public class DeppDemo {
private String aaa;
public void abc(String aaa) {
this.aaa = aaa;
}
public static void main(String[] args) {
DeppDemo demo = new DeppDemo();
demo.abc("New value");
System.out.println(demo.aaa);
}
}

Static class properties with Class<MyClass> myClass

I am experimenting here a bit.
Say I have a class :
static class MyClass {
static String property = "myProperty";
}
and a method:
public static void myMethod0(Class<MyClass> clazz) {
try {
MyClass myClass = clazz.newInstance();
System.out.println (myClass.property);
} catch (Exception e) {
e.printStackTrace();
}
}
and to test it:
public static void main(String[] args ) {
myMethod0(MyClass.class);
}
myMethod0 would work here, however, I am creating a new instance in order to reach the property.
Since the properties are static I should be able to reach them without actually creating any instance. For example as you would do when reaching a static property, ie MyClass.property
To summarize:
Is it possible to reach the static property of MyClass, by having Class clazz = MyClass.class ?
Thanks !
**
EDIT:
**
To put the above in perspective and what I am actually trying to accomplish:
public static class PDF_1 { public static PDF_1 it = new PDF_1();
static String contentType = "application/pdf";
static String fileEnding = "pdf";
}
static void myMethod0(PDF_1 pdf) {
System.out.println(pdf.fileEnding);
}
public enum PDF_2 {it;
static String contentType = "application/pdf";
static String fileEnding = "pdf";
}
static void myMethod1(PDF_2 pdf) {
System.out.println(pdf.fileEnding);
}
public static void main(String[] args ) {
myMethod0(PDF_1.it); // Works fine! However very verbose because of public static PDF_1 it = new PDF_1();
myMethod1(PDF_2.it); // Works fine! Somewhat verbose though because of the "it" keyword
}
The whole idea as to what I am trying to accomplish with this, is that too often do I see people declare lots of strings, ie:
static class Constants {
static String PDF_CONTENT_TYPE = "application/pdf";
static String PDF_FILE_ENDING = "pdf";
static String HTML_CONTENT_TYPE = "text/html";
static String HTML_FILE_ENDING = "html";
}
// There is no way knowing what type the method actually wants. Is it contentType, fileEnding or something entirely different ?
public void myMethod(String str) {
}
What I am trying to achieve is something that would allow you to pass a main class/enum, ie: PDF and the method will itself determine what it will use. The caller will just know what to pass, a PDF or HTML class/enum. I am also looking for something that is this refactor friendly as well. It is also of interest not to complicate the declaration of this creation. I find fully blown enums just as obtrusive as a class, and can be hard to read. The ide a is that I am just grouping the two strings in a parent object "PDF" and "HTML". An enum:
public enum SomeType {
PDF("application/pdf", "pdf"), HTML(...);
String contentType;
String fileEnding;
// Constructor ...
}
Would not allow you to declare a method and specify that this method expects the HTML stuff. Only that the enum type is of type SomeType. There is a risk that "someone" would pass SomeType.PDF to that method. What I am doing with the enum and class seems like a noob solution, and the Java language should provide a feature like this, or does it already?
Does this make sense?
You could use reflection
System.out.println(myClass.getDeclaredField("property").get(null));
The get-method usually requires an instance to get the attribute from, but since property is static, you may pass it a null.
I hope you meant this - I wrote tests with hamcrest - so don't wonder ;)
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.Matchers.*;
import org.junit.Test;
public class TestEnumEnding {
#Test
public void whenMethod1WithFiletypeHtmlWeShouldGetStringText_Html() throws Exception {
// Arrange
String contentType = null;
// Act
contentType = method1(Filetype.HTML);
// Assert
assertThat(contentType, is("text/html"));
}
#Test
public void whenMethod1WithFiletypePdfWeShouldGetapplication_pdf() throws Exception {
// Arrange
String contentType = null;
// Act
contentType = method1(Filetype.PDF);
// Assert
assertThat(contentType, is("application/pdf"));
}
private static String method1 (Filetype anyFiletype) {
return anyFiletype.getContentType();
}
public enum Filetype {
HTML("html","text/html"), PDF("pdf","application/pdf");
private final String fileEnding;
private final String contentType;
private Filetype(String fileEnding, String contentType) {
this.fileEnding = fileEnding;
this.contentType = contentType;
}
public String getFileEnding() {
return this.fileEnding;
}
public String getContentType() {
return this.contentType;
}
}
}
public enum PDF { it;
static String contentType = "application/pdf";
static String fileEnding = "pdf";
}
static void myMethod1(PDF pdf) {
System.out.println(pdf.fileEnding);
}
public static void main(String[] args ) {
myMethod1(PDF.it); // Works fine! Somewhat verbose though because of the "it" keyword. Not 100% ideal!
}

Categories

Resources