仅允许从某些包中构建对象

时间:2013-05-25 16:31:20

标签: java packages

我在类似游戏的系统上工作。用户可以提交.class和.java文件以进行自定义行为。一些对象通过回调传递给用户,但如果用户可以自己构建这些对象(使用自定义参数),则对他来说意味着一个优势。我将禁止用户反思并密封我的包裹。如果我放弃所有的包结构(并使构造函数包私有),我可以得到这个工作,但我不想这样做。


以下是一个例子:

sscce.mycode.a.SomeClass.java

package sscce.mycode.a;

import sscce.mycode.b.RestrictedObject;
import sscce.usercode.SomeUserClass;

public class SomeClass {

    public static void main(String[] args) {
        SomeUserClass userClass=new SomeUserClass();

        // If I can create it from here, anyone can...
        RestrictedObject object=new RestrictedObject();

        userClass.someMethod(object);
    }

}

sscce.mycode.b.Interface.java

package sscce.mycode.b;

public interface Interface {

    public void someMethod(RestrictedObject restrictedObject);

}

sscce.mycode.b.RestrictedObject.java

package sscce.mycode.b;

public class RestrictedObject {

    public RestrictedObject() {}

}

sscce.usercode.SomeUserClass.java

package sscce.usercode;

import sscce.mycode.b.Interface;
import sscce.mycode.b.RestrictedObject;

public class SomeUserClass implements Interface {

    @Override
    public void someMethod(RestrictedObject restrictedObject) {
        // It receives an instance, but cannot create it.
        System.out.println("Got "+restrictedObject);
    }
}

动机:将所有内容放在一个包中听起来很麻烦......

有没有人有关于如何在不展平包装的情况下实现这一目标的想法? 提前感谢任何解决方案,想法或评论,直到

1 个答案:

答案 0 :(得分:1)

你可以通过以下方式实现,但是你应该仔细考虑是否真的想要使用这种方法,因为它非常缓慢而且非常坦率地说是不好的做法。 无论如何,无论如何可以这样做,我都会提出来:

public final class Secured {

  private static final Set<Class<?>> allowedCallers = new HashSet<>();

  static {
    allowedCallers.add(Allowed.class);
  }

  private static final class SecurityManagerExtension extends SecurityManager {

    private static final int OFFSET = 4;

    @Override
    protected Class<?>[] getClassContext() {
      return super.getClassContext();
    }

    private Class<?> getCaller() {
      try {
        return getClassContext()[OFFSET];
      } catch (ArrayIndexOutOfBoundsException e) {
        return null;
      }
    }
  }

  private Secured() {
    // protect against reflection attack
    Class<?> caller = new SecurityManagerExtension().getCaller();
    if (!this.getClass().equals(caller)) {
      throw new IllegalStateException();
    }
    System.out.println("Secured instance constructed!");
  }

  public static Secured createInstance() {
    // this gets the class name of the calling class
    Class<?> caller = new SecurityManagerExtension().getCaller();
    if (allowedCallers.contains(caller)) {
      System.out.println("Created instance by '" + caller + "'!");
      return new Secured();
    } else {
      System.out.println("No instance created because call was made by '" + caller + "'!");
      return null;
    }
  }
}

注意类上的final关键字以防止子类化。如果您需要自己创建类的子类,请将final关键字移动到工厂方法。 另请注意,这不受序列化攻击的保护。