在Java中对方法体施加约束或限制 上下文(编辑)
一些澄清是按要求进行的,所以我将尝试总结一下是什么影响了这个问题在Java中对方法体施加约束或限制 上下文(编辑),java,architecture,methods,constraints,invariants,Java,Architecture,Methods,Constraints,Invariants,一些澄清是按要求进行的,所以我将尝试总结一下是什么影响了这个问题 该项目的目标是为程序员提供某种功能,最有可能的形式是一个库(我想是一个带有类文件的JAR) 要使用上述功能,程序员必须遵守必须(应该)满足的约束。否则它将无法正常工作(就像java.util.concurrent中的锁一样,必须在适当的时间和地点获取/释放这些锁) 此代码不会成为使用它的应用程序的入口点(即,没有main) API中公开的操作数量有限(而且很少) 示例: 想想一个小游戏,几乎所有的东西都是由已经实现的类实现和管
- 该项目的目标是为程序员提供某种功能,最有可能的形式是一个库(我想是一个带有类文件的JAR)
- 要使用上述功能,程序员必须遵守必须(应该)满足的约束。否则它将无法正常工作(就像
中的锁一样,必须在适当的时间和地点获取/释放这些锁)java.util.concurrent
- 此代码不会成为使用它的应用程序的入口点(即,没有
)main
- API中公开的操作数量有限(而且很少)
行走
,或者更改方向
,或者计算diff=desiredValue-x
,而不是写入某个文件,或者打开套接字连接读取
、写入
、提交
、或回滚
。我不想让他们在交易过程中<代码>发射火箭< /代码>,如果管理者不控制任何火箭发射。public abstract class ToBeExtended {
// some private stuff they should not modify
// ...
public abstract SomeReturnType safeMethod();
}
对于这个项目来说,方法体满足一些不变量是很重要的(可能是必须的)。或者更确切地说,该方法实现使用的命令集必须是有限的。这些限制的示例:
- 此方法不得执行任何I/O
- 此方法不能实例化任何未知(潜在危险)对象
- 此方法可以调用已知(特定)类的方法
- 此方法可以执行一些基本指令(数学、分配局部变量、
s、循环…)if
我目前的选择:
@SafeAnnotation
,并将其应用于方法,定义与实施者的契约,以确保他将遵守强加的规则,否则系统将出现故障Enum
。不是公开允许的方法,而是只公开一个方法,该方法接受这些枚举对象的列表(或类似于枚举对象的东西)并执行它,让我控制可以做什么public enum AllowedOperations { OP1, OP2 }
public class TheOneKnown {
public void executeMyStuff (List<AllowedOperations> ops) {
// ...
}
}
公共枚举允许的操作{OP1,OP2}
公共类TheOneKnown{
public void executeMyStuff(列表)。尽管如此,这可能需要重新考虑体系结构
使用注释来限制的整个想法似乎需要实现我自己的注释处理器。如果是这样的话,我不妨考虑一个小的域特定语言,这样程序员就可以使用这些有限的操作,然后把代码翻译成java。这样,我也可以控制什么是指定的。d、
Java有几个可用的库,但我不能特别推荐一个。这似乎是一个轻量级的解决方案,但再一次,我没有使用它的第一手经验。看看Java策略文件。我没有使用过它们,我不确定它们是否完全适合您的问题,但需要深入研究文档他们可能很适合。这里有几个问题可能会有帮助
这里有一些关于政策文件的文档
您可以使用自定义类加载器限制不受信任代码使用的类:
public class SafeClassLoader extends ClassLoader {
Set<String> safe = new HashSet<>();
{
String[] s = {
"java.lang.Object",
"java.lang.String",
"java.lang.Integer"
};
safe.addAll(Arrays.asList(s));
}
@Override
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
if (safe.contains(name)) {
return super.loadClass(name, resolve);
} else {
throw new ClassNotFoundException(name);
}
}
}
public class Sandboxer {
public static void main(String[] args) throws Exception {
File f = new File("bin/");
URL[] urls = {f.toURI().toURL()};
ClassLoader loader = new URLClassLoader(urls, new SafeClassLoader());
Class<?> good = loader.loadClass("tools.sandbox.Good");
System.out.println(good.newInstance().toString());
Class<?> evil = loader.loadClass("tools.sandbox.Evil");
System.out.println(evil.newInstance().toString());
}
}
public class Good {
@Override
public String toString() {
return "I am good";
}
}
public class Evil {
@Override
public String toString() {
new Thread().start();
return "I am evil.";
}
}
当然,这需要注意白名单中的类。它也不能防止拒绝服务,例如
while (true) {}
或
另一种选择是使用en嵌入式脚本解释器,例如groovy one(),并在运行时通过预执行验证来评估第三方方法的内容
优点是,您可以将访问权限限制为仅限于将为脚本执行绑定的变量
您还可以编写自己的验证dsl,并将其应用于执行脚本的方法,例如使用自定义注释。我认为方向是好的
- 使用特定的
ClassLoader
加载类。注意,它们是一种有趣的类型,通常情况下,类本身由父类加载器加载。可能您需要某种类型的类加载器,而父类加载器将设置为根类加载器,但这是不够的
- 使用
threads
避免无限循环(而不是实现Runnable
而不是像这样扩展Thread
),如果您不担心的话,这可能是不必要的
- 使用SecurityManager避免
java.io
操作
除上述内容外,我推荐两个选项:
为该方法提供一个控制器,这将
while (true) {}
new long[1000000000];
public void foo(Controller ctrl) {
}
public class Controller {
public boolean commit();
public boolean rollback();
}