0
\$\begingroup\$

I have become interested in reflection and I wrote a class to wrap an Object so that I can access its private instance fields. The code works great. I do not need to wory about the exceptions in the get() and set() methods because I cast the values appropriately through my wrappers accessor/mutators, but I was wondering if there is a better way of dealing with different types?

Example

public class Driver {
    public static void main(String... args) {
        Point p = new Point();

        System.out.printf("Point initialized: %s\n", p);

        PointDecorator mp = new PointDecorator(p);

        mp.setX(2);
        mp.setY(4);

        p = mp.getPoint();

        System.out.printf("Point updated:     %s\n", p);
    }
}

Output

Point initialized: (0, 0)
Point updated:     (2, 4)

As you can see, I have modified the Point Objects fields, although they are inaccessible through traditional method calls. I was able to bypass Java's typechecking which I find both neat and dangerous. Does this mean that anyone can just wrap another persons class, unless it is immutable, and inject data?

Point.java

public class Point {
    private int x, y;

    public Point() {
        this(0, 0);
    }

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public String toString() {
        return String.format("(%d, %d)", x, y);
    }
}

PointDecorator.java

import java.lang.reflect.Field;

public class PointDecorator extends Point {

     protected Point point;

    public PointDecorator(Point point) {
        this.point = point;
    }

    public void setX(int x) {
        set("x", x);
    }

    public int getX() {
        return (Integer) get("x");
    }

    public void setY(int y) {
        set("y", y);
    }

    public int getY() {
        return (Integer) get("y");
    }

    public Point getPoint() {
        return point;
    }

    protected Object get(String fieldName) {
        try {
            return field(fieldName).get(point);
        } catch (Exception e) { }

        return null;
    }

    protected void set(String fieldName, Object value) {
        try {
            field(fieldName).set(point, value);
        } catch (Exception e) { }
    }

    private Field field(String fieldName) {
        try {
            Field f = point.getClass().getDeclaredField(fieldName);
            f.setAccessible(true);
            return f;
        } catch (Exception e) { }

        return null;
    }
}
\$\endgroup\$

closed as off-topic by 200_success Mar 6 '16 at 11:00

This question appears to be off-topic. The users who voted to close gave this specific reason:

If this question can be reworded to fit the rules in the help center, please edit the question.

  • 2
    \$\begingroup\$ This question appears to be off-topic because the code to be reviewed is not 'actual code from a project' and but is 'pseudo-code or example code'. It belongs to programmers SE. \$\endgroup\$ – abuzittin gillifirca Nov 26 '13 at 12:50
4
\$\begingroup\$

Essentially you are after the answer to:

Does this mean that anyone can just wrap another persons class, unless it is immutable, and inject data?

And you are not really interested in a review of your code... right? (By the way, your code looks neat, and covers the bases of your 'academic exercise' quite well).

Java reflection is a dangerous process. On the up-side, reflection is regulated by the Java security system, and it can be enabled or disabled depending on the site, situation, and whatever else people are worried about.

So, if someone has code in your JVM, then they have access to the internals of your program (assuming Java has a permissive setting for it's security - which is the 'default'). On the other hand, other languages (C, cough *cough*) have even more of a problem if someone has been able to 'inject' malicious code in to their program.

It is all about relative-ness. Relative to many languages, Java is quite safe, and it has ways of being even safer.

On the other hand, if you let someone untrusted run code on your JVM then you have bigger problems to worry about.... ;-)

For what it's worth, there are easier ways to produce problematic code, like deserializing 'malicious' instances of values, or simply manipulating the JVM classpath before the program launches.

It's all about perspective....

\$\endgroup\$
  • \$\begingroup\$ Well, I don't know too much about decorators, but I believe I am doing looks correct? Sorry I guess I was really asking for assurance. I thought it was neat and didn't actually think it would work at first :-p \$\endgroup\$ – Mr. Polywhirl Nov 26 '13 at 2:33
  • 1
    \$\begingroup\$ The Point's internal x and y ar enot final, so that's one thing, and you do have it a little bit easier because you are only playing with primitive fields, and not methods and consructors. It gets a little bit hairy when you are dealing with things like constructors that have arrays of primitives (like double[]) arguments. Reflection gets complicated fast. You chose the 'hello world' problem to start on (which is a good thing) \$\endgroup\$ – rolfl Nov 26 '13 at 2:41
  • 1
    \$\begingroup\$ Just wanted to add this: Just because a field is final doesn't mean that it can't be modified with reflection. Which is something @Mr.Polywhirl should be aware about regarding reflection. \$\endgroup\$ – Simon Forsberg Nov 26 '13 at 13:24

Not the answer you're looking for? Browse other questions tagged or ask your own question.