Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find the object that called a method in Java

can I find the object who called a method in Java? I have a social network with groups and persons. If a person wants to leave a group, only that can remove itself from the group, nobody else can remove that person, somehow the person who called the method must prove it's identity.

like image 781
John Smith Avatar asked Mar 11 '13 00:03

John Smith


People also ask

How do you find out who called a method in Java?

Sometimes it is nice to access the caller of a method. Doing this is relatively simple, you can use the getStackTrace() method on the current thread.

How do you reference a call object in Java?

Calling an Object's Methods. You also use an object reference to invoke an object's method. You append the method's simple name to the object reference, with an intervening dot operator (.). Also, you provide, within enclosing parentheses, any arguments to the method.

How does an object call a method?

Calling an object's method is similar to getting an object's variable. To call an object's method, simply append the method name to an object reference with an intervening '. ' (period), and provide any arguments to the method within enclosing parentheses.


1 Answers

Checking the callers of a method is a quite common request from inexperienced programmers. I'm surprised that it doesn't appear more often on SO. But it's a really incredibly bad idea (just check out the Java 2 (and perhaps worse earlier) Security Model).

There are few circumstances where it's important to implement this restriction. As Oli Charlesworth say, just don't do it. But let's assume that it is important, but we're not going to do stack inspection.

Let's start by assuming we trust the group. A working but nonsensical approach is to pass to the group an object standing in for the person that only the person can create. (Note Java language access restrictions are class-based. A different instance could create such a stand in, but the code would have to be within the Person class.)

public final class Group { // Can't have a malicious subclass.
    public void deregisterPerson(Person.Standin standin) {
        Person person = standin.person();
        ...
    }
}
public class Person { // May be subclassed.
    public final class Standin { // Could be one per Person.
        private Standin() { // Hide constructor from other outer classes.
        }
        public Person person() {
            return Person.this;
        }
    }
    private void groupDeregister(Group group) {
        group.deregisterPerson(new Standin());
    }
 }

If we don't trust the group, then we could extend the stand-in to reference the group. This prevents a malicious group deregistering a person from other groups.

public class Group { // Can have malicious subclasses.
    public void deregisterPerson(Person.GroupDeregister deregister) {
        if (deregister.group() != this) { // Not equals...
            throw new IllegalArgumentException();
        }
        Person person = deregister.person();
        ...
    }
}
public class Person { // May be subclassed.
    public final class GroupDeregister {
        private final Group group;
        private GroupDeregister(Group group) { // Hidden.
            this.group = group;
        }
        public Person person() {
            return Person.this;
        }
        public Group group() {
            return group;
        }
    }
    private void groupDeregister(Group group) {
        group.deregisterPerson(new GroupDeregister(group));
    }
 }

Another approach is to make a "public" version of Person that can be exposed to others.

public class Person { // "PrivatePerson"
    public PublicPerson publicPerson() {
         return new PublicPerson(this);
    }
    private void groupRegister(Group group) {
        group.registerPerson(this);
    }
    private void groupDeregister(Group group) {
        group.deregisterPerson(this);
    }
    ...
}
public class PublicPerson {
    private final Person person;
    public PublicPerson(Person person) {
        this.person = person;
    }
    @Override public final boolean equals(Object obj) {
        return obj instanceof Person && (Person)obj.person == person;
    }
    @Override public final int hashCode() {
        return person.hashCode();
    }
    ...methods, but no raw registration...
 }
 public class Group {
     private final Set<Person> members = new IdentityHashSet<>(); // No Object.equals.
     public void registerPerson(Person person) {
         members.add(person);
     }
     public void deregisterPerson(Person person) {
         members.remove(person);
     }
     public Set<PublicPerson> members() {
         // This will be more concise in Java SE 8.
         Set<PublicPerson> publics = new HashSet<>();
         for (Member member : members) {
             publics.add(member.publicPerson());
         }
         return unmodifiableSet(publics);
     }
}

(Objects.requireNonNull left out for "brevity".)

like image 109
Tom Hawtin - tackline Avatar answered Sep 28 '22 07:09

Tom Hawtin - tackline