Java: Using reflection to fill all the setters from a class - java

I have a class X with maybe 100 String in it and I want to do a function that mock an object of this class for all the setters which begins by "setTop".
For the moment I did this :
public void setFtoMethods(Class aClass){
Methods[] methods = aClass.getMethods();
for(Method method : methods){
if(method.getName().startsWith("setTop")){
method.invoke ....
}
}
}
And I don't know how to do now and I'm not pretty sure I can fill all these setters like that. In my environment I can't use frameworks and I'm in Java 6.

You CANNOT fill the setters because they are methods (functionallities), not values itselfs. But...
You CAN fill the value of the attributes (fields) of the class that corresponds to the getter.
Imagine you have a class:
class Example {
String name;
int topOne;
int topTwo;
int popTwo; // POP!!!
int topThree;
}
Taking:
this answer as model
your needs (getTopXXX will correspond to field topXXX)
You can get only needed fields with reflection in this way:
public static void main(String[] args) {
inspect(Example.class);
}
public static <T> void inspect(Class<T> klazz) {
Field[] fields = klazz.getDeclaredFields();
for (Field field : fields) {
if (field.getName().startsWith("top")) {
// get ONLY fields starting with top
System.out.printf("%s %s %s%n",
Modifier.toString(field.getModifiers()),
field.getType().getSimpleName(),
field.getName()
);
}
}
}
OUTPUT:
int topOne
int topTwo
int topThree
Now, do whatever you need inside the if (field.getName().startsWith("top")) { instead of a System.out.

Related

Check if class has a variable in its constructor based on a string?

Let's say I have a class named Person and its constructor had variables like name, age, hairColor and so on. If I had a function that receives a string that should match one of the class's variables, how could I check if that class actually had that variable and how could I go about modifying it? For example:
public class Person {
public String name;
public int age;
public String hairColor;
public Person() {
name = "Bryce";
age = 21;
hairColor = "brown";
}
public void changeHairColor(String variable, String color) {
if (/*this class contains the variable passed as an argument to this method*/) {
// Person[variable] = color
}
}
}
I'm a python dev, mostly, so the method changeHairColor has some pseudo-python in it. I want to be able to edit the variable in a similar way you could edit variables inside of dictionaries with Python:
person = {
"name": "Bryce",
"age": 21,
"hairColor": "brown"
}
def changeHairColor(variable, color):
person[variable] = color
If that is at all possible.
The only way to do it in Java is to use Java Reflection API:
public class Test {
public String name;
public int age;
public String hairColor;
public void setProperty(String property, Object value) {
try {
Field declaredField = this.getClass().getDeclaredField(property);
switch (declaredField.getAnnotatedType().getType().getTypeName()) {
case "java.lang.String":
declaredField.set(this, value);
break;
// handle other types
}
} catch (NoSuchFieldException e) {
// handle exception
} catch (IllegalAccessException e) {
// handle exception
}
}
public static void main(String[] args) {
Test test = new Test();
test.setProperty("name", "Bob");
System.out.println(test.name);
}
}
I would not solve this with reflection. If your PlayerCharacter has an enumerable set of attributes, I would model these as a Java enum and store the attribute values within the PlayerCharacter object in an EnumMap:
import java.util.EnumMap;
public class PlayerCharacter {
public enum Attribute {
AGILITY,
DEXTERITY,
/* etc ...*/
VITALITY
}
private EnumMap<Attribute, Integer> attributes = new EnumMap<>(Attribute.class);
public PlayerCharacter() {
// initialize each attribute with a default value (0 in this example)
for (Attribute a : Attribute.values()) {
attributes.put(a, new Integer(0));
}
}
public int getValue(Attribute attribute) {
return attributes.get(attribute);
}
public void levelUp(Attribute attribute, int amount) {
attributes.put(attribute, attributes.get(attribute) + amount);
}
}
The biggest benefit of using an enum instead of plain old String (+reflection), is that this way you get compile-time type safety for the code that's using your PlayerCharacter.
Using Reflection API, you can access the methods and properties on an object at run time. The other answer describes its usage. But I don't recommend reflections for your problem. How about the following:
public void changeHairColor(String variable, String color) {
if("name".equalsIgnoreCase(variable))
this.name = color;
else if("age".equalsIgnoreCase(variable))
this.age = Integer.parseInt(color);
else if("color".equalsIgnoreCase(variable))
this.color = color;
else
throw new Exception ("error - property not available");
}
}
Note, your existing method name 'changeHairColor' doesn't make sense in the context. It should be someething like 'changeProperty' because you are not just changing the 'color', you are changing any available property with this method.

Shared multiple class for ToString implementation

I have multiple pojo classes using below code.
public class ToStringImpl {
public String toString(){
StringBuilder result = new StringBuilder();
String newLine = "\n";
result.append( this.getClass().getName() );
result.append( " Data {" );
result.append(newLine);
//determine fields declared in this class only (no fields of superclass)
Field[] fields = this.getClass().getDeclaredFields();
//print field names paired with their values
for ( Field field : fields ) {
result.append(" ");
try {
result.append( field.getName() );
result.append(": ");
//requires access to private field:
result.append( field.get(this) );
} catch ( IllegalAccessException ex ) {
System.out.println(ex);
}
result.append(newLine);
}
result.append("}");
return result.toString();
}
}
How do I call above class from different classes?
Suppose I have pojo classes called customer, store, inventory
public class Customer {
private String name;
private String address;
...getter...setter...
public String toString(){
ToStringImpl log = new ToStringImpl();
//how do I pass different classes here?
return log.toString();
}
}
public class Store {
private String logo;
private String type;
....getter...setter...
}
public class Inventory {
private boolean isAvailable;
private long index;
...getter...setter
}
for each class how do I pass different class? or if there are better way to do this? or would it be better to create toString as interface and implement it in each class and pass it as constructor?
What you can do is make the toString() method in the ToStringImpl class static. I wouldn't call it toString() though, change it to something like getClassString()
Example:
public static String getClassString(Object o)
{
StringBuilder result = new StringBuilder();
String newLine = "\n";
result.append(o.getClass().getName());
result.append(" Data {");
result.append(newLine);
// determine fields declared in this class only (no fields of
// superclass)
Field[] fields = o.getClass().getDeclaredFields();
// print field names paired with their values
for (Field field : fields)
{
result.append(" ");
try
{
result.append(field.getName());
result.append(": ");
// requires access to private field:
result.append(field.get(o));
}
catch (IllegalAccessException ex)
{
System.out.println(ex);
}
result.append(newLine);
}
result.append("}");
return result.toString();
}
Then in your POJO classes, call it with:
public String toString()
{
// how do I pass different classes here?
// by passing the 'this' reference
return ToStringImpl.getClassString(this);
}
There is already a library that does this. Look up ToStringBuilder in the apache-commons library, your domain objects' toString method would look like:
#Override public String toString() {
return ToStringBuilder.reflectionToString(this);
}
The best plan would seem to me to be to rip out the homegrown code and drop in apache-commons, or use Project Lombok. If you must reinvent this wheel then copying ToStringBuilder's example of using a static method and taking the object to print as a parameter would be reasonable.
The ToStringBuilder includes a feature to let you restrict which fields get printed, your own code should do something similar for the sake of your own sanity. The toString method is used to print out information for debugging and logging. If you just get all the fields like your posted code it will dump out the entire object's contents every time you call toString in a log entry and you will have something that's unreadable, it will fill up your logs and slow down your application writing all this information.
You are the consumer of the information here, make it something that's useful instead of being overwhelming.
When you override a method, for example Object#toString(), you only override it for that class. You can do one of the following:
Add your toString() to every class that might need it and then just call toString() on that object from wherever it is. (not recommended)
extend your ToStringImpl on every class you want to and call toString() on object.
Make ToStringImpl#toString() static and pass an object as argument (recommended), for example:
public static void objectToString(Object ob){
//your code here, just replace "this" with "ob"
}

Calling an array from a different class - Java

How can I access my array from a different class? I have 3 classes; Main (where I want to access the array from) FramePanel (my GUI and where the value from UserInputNum is taken from) and StoryArray (where my array is saved).
I need to access the array in the nested If loop in the Main class, this is because I want too save the specific array data to a string and eventually append it into a JTextArea.
Here are the two classes needed:
Main.java
public class Main
{
public static String UserInput;
public static int UserInputNum;
public static void main(String[] args)
{
FramePanel.main();
StoryArray.main();
UserInputNum = Integer.parseInt(UserInput);
if (UserInputNum >= 0)
{
if (UserInputNum <= 399)
{
StoryArray.storyLine[UserInputNum];
}
else
{
}
}
else
{
}
}
}
StoryArray.java
public class StoryArray
{
public static String storyLine[] = null ;
public String[] getStoryLine()
{
return storyLine;
}
public static void main()
{
//String[] storyLine;
storyLine = new String[399];
storyLine[0] ("1")
storyLine[1] ("2")
storyLine[2] ("3")
storyLine[3] ("4")
storyLine[4] ("5")
storyLine[5] ("6")
In another class you can call the array like this:
String value = StoryArray.storyLine[index];
As it is a static public field you can access it directly by StoryArray.storyLine. But as you have a getter ethod I would suggest to make this getter setter static and the array field private and access it through getter method like that: StoryArray.getStoryLine() (to see why read about encapsulation).
You also shouldn't start your class (main) name from lower case, here are standard coding conventions for java language: http://www.oracle.com/technetwork/java/codeconvtoc-136057.html
Once you've called StoryArray.main(), then you should be able to do StoryArray.storyLine[/*element id*/] = "whatever you want" to get or set any element in storyLine. Additionally, you aren't defining any default array values. In StoryArray.main(), you need to have lines of the form storyLine[n] = "n".

Is there some similar feature in Java as 'attributes' in Delphi?

Is there some similar feature in Java as 'attributes' in Delphi ?
Example explanation of Attributes in Delphi:
http://www.malcolmgroves.com/blog/?p=476
Att.
From that article, you're looking for Java Annotations. They let you do things like:
#SomeInfo(author = "Bob", year = 1993)
class Foo {
#SomeInfo(author = "me", somethingElse = "abcdefg")
private int x = 5;
#SomeInfo(author = "Fred", column = "order")
public int getX() {
return x;
}
}
where #SomeInfo is an annotation. They can be applied to classes, fields, and methods, and they carry metadata about the thing they annotate, which can be read at runtime if they have the appropriate retention. E.g:
#Retention(RetentionPolicy.RUNTIME)
#interface SomeInfo {
String author();
int year() default -1;
String column() default "";
String somethingElse() default "";
}
class Main {
public static void main(String[] args) throws Exception {
List<AnnotatedElement> annotatedElements =
new ArrayList<AnnotatedElement>();
annotatedElements.add(Foo.class);
annotatedElements.add(Foo.class.getDeclaredField("x"));
annotatedElements.add(Foo.class.getDeclaredMethod("getX"));
for (AnnotatedElement annotatedElement : annotatedElements) {
System.out.println("Author of {" + annotatedElement + "} = " +
annotatedElement.getAnnotation(SomeInfo.class).author());
}
}
}
It looks like an attributes is a way to store diffrent variable together.
That is what OOP is (Very)generally about (And so is JAVA), creating classes that represents entities. Those entities are basically made of different variables (or attributes)
This example from your link and a comparison to JAVA will make it clearer:
MyAttribute = class(TCustomAttribute)
private
FName: string;
FAge: Integer;
public
constructor Create(const Name : string; Age : Integer);
property Name : string read FName write FName;
property Age : Integer read FAge write FAge;
end;
Is just like a little class in JAVA:
public class Customer()
{
String Fname;
int FAge;
public Customer()
{
/*constructor code*/
}
}
and creating the class from your example:
TMyClass = class
public
[MyAttribute('Malcolm', 39)]
Is just like creating a new person object:
Customer[] cust1= new Customer['Malcolm', 39]

Dynamically return a list of all class variable values in Java

I am creating a helper class in parsing XML elements, so the developer do not need to know the exact name and capitalization of the XML fields.
private static class TagNames{
public static String RESOURCE_ID = "ResourceId";
public static String RESOURCE_NAME = "ResourceName";
public static String RESOURCE_PRICE = "ResourcePrice";
}
This makes it easier to do things like:
someXMLParser.getValueByTagName(TagNames.RESOURCE_ID);
My question is this. If I want to iterate over all the fields declared in class TagNames, how do I do that? Pseudocode:
For tag in TagNames:
someXMLParser.getValueByTagName(tag)
I know I will probably have to restructure all of this. But I can't figure out a way to make the names easily accessible as well as iterable, without any duplication.
Any suggestions?
You're literally asking for a solution based on reflection, but I think a Java Enum may be a better choice in this case. Building on Frederick's example:
public class EnumTest {
public enum Tags {
RESOURCE_ID("ResourceId"),
REOURCE_NAME("ResourceName"),
RESOURCE_PRICE("ResourcePrice");
private final String tagName;
Tags(String tagName) {
this.tagName = tagName;
}
public String getTagName() {
return tagName;
}
}
public static void main(String[] args) {
for(Tags tag : Tags.values()) {
System.out.println("const:" + tag.name()
+ " tagName:" + tag.getTagName());
}
// API user might do e.g.:
// document.getValueForTag(Tags.REOURCE_NAME);
}
}
Although I agree that you should probably use enums or ResourceBundles, here's a solution to your actual question. A method that generates a Map name -> value from all public constants in a given class (the only thing that's missing should be try / catch or throws)
public static Map<String, Object> getConstantValues(Class<?> clazz){
Map<String, Object> constantValues = new LinkedHashMap<String, Object>();
for(Field field : clazz.getDeclaredFields()){
int modifiers = field.getModifiers();
if(Modifiers.isPublic(mod)
&& Modifiers.isStatic(mod) && Modifiers.isFinal(mod)){
constantValues.put(field.getName(), field.get(null));
}
}
return constantValues;
}
You may want to consider using a ResourceBundle instead of a class to store the tag names. May require a little bit of reworking of your code but it will be easier to produce a list of tags compared to what you are doing now, and adding a new tag won't require much work other then adding a line to the properties file.
You can do this quite easily using enum and an accompanying array:
public class Main {
public enum TagName { RESOURCE_ID, REOURCE_NAME, RESOURCE_PRICE }
private static String[] tags = {"ResourceID", "ResourceName", "ResourcePrice"};
public static String getValueByTagName(TagName tag) {
return tags[tag.ordinal()];
}
public static void main(String[] args) {
System.out.println("Calling by getValueByTagName:");
System.out.println(getValueByTagName(TagName.RESOURCE_ID));
System.out.println("Calling TagName.values() for loop:");
for (TagName t : TagName.values()) {
System.out.println(getValueByTagName(t));
}
}
}
Using an enum is a good fit, especially if you use a custom constructor and the built in "values" method:
public class Main {
public static enum TagName {
RESOURCE_ID("ResourceId"),
RESOURCE_NAME("ResourceName"),
RESOURCE_PRICE("ResourcePrice"),
;
private String s;
private TagName(String s) { this.s = s; }
public String toString() { return this.s; }
public static String[] strings() {
List<String> ss = new ArrayList<String>();
for (TagName tagName : TagName.values()) {
ss.add(tagName.toString());
}
return ss.toArray(new String[ss.size()]);
}
}
public static void main(String[] args) {
// Use TagName.values() for the enums, or for strings...
for (String s : TagName.strings()) {
System.out.println(s);
}
}
}
This way you can simply add new tags and they'll automatically get picked up by the "strings" method; for extra performance you could compute that string array just once, statically, since you can't change the set of enums dynamically. You could get even fancier by auto-generating the tag strings from their constant values, if they are really normalized...

Categories