Наложение ограничений или ограничений на тело метода в Java

Контекст (Редактировать)

некоторые разъяснения были по требованию, поэтому я попытаюсь подвести итог, что влияет на вопрос.

  • цель проекта-предоставить программистам определенную функциональность, скорее всего, в виде библиотеки (банка с файлами классов, я думаю).

  • чтобы использовать указанную функциональность, программисты должны были бы соответствовать ограничениям, которые должны (должно) быть удовлетворены. В противном случае он не будет работать так, как ожидалось (так же, как замки из java.util.concurrent, который должен быть приобретен / освобожден в соответствующее время и место).

  • этот код не будет точка входа в приложения, использующие его (ie, нет main).

  • существует ограниченное (и небольшое) количество операций, предоставляемых в API.

примеры:

  1. думаю небольшой игры, где практически все реализовано и управляется уже реализованными классами. Единственное, что остается программисту сделать, это написать метод или несколько из них, которые описывают, что будет делать персонаж (ходить, менять направление, останавливаться, проверять объект). Я хотел бы убедиться, что их методы (возможно, помечены аннотацией?) просто walk или changeDirection, или расчета diff = desiredValue - x, а не, скажем, писать в какой-то файл или открывать сокет соединение.

  2. подумайте о менеджере транзакций. Менеджер будет предоставлен этой библиотекой, а также некоторые постоянные атрибуты транзакций (их уровень изоляции, тайм-ауты,...). Теперь программисты хотели бы иметь транзакции и использовать этот менеджер. Я хотел бы убедиться, что они только read, write, commit или rollback на некоторых ресурсах, известный менеджер. Я бы не хотел, чтобы они ... --11--> в середине транзакции, если менеджер не контролирует запуск ракет.

Проблема

я хочу наложить некоторые инварианты / ограничения/ограничения на тело метода (или группы методов), которые позже будут реализованы каким-либо другим программистом в каком-либо другом пакете / местоположении. Скажем, я даю им что-то вроде:--18-->

public abstract class ToBeExtended {
    // some private stuff they should not modify
    // ...
    public abstract SomeReturnType safeMethod();
}

для целей этого проекта важно (возможно, императивно), чтобы тело метода удовлетворяло некоторым инварианты. Или, скорее, необходимо, чтобы набор команд, используемых в реализации этого метода, был ограничен. Примеры этих ограничений:

  • этот метод не должен выполнять никаких операций ввода-вывода
  • этот метод не должен создавать какие-то неизвестные (потенциально опасные) объекты.
  • ...

иными словами:

  • этот метод может вызывать методы известного (определенного) класс.
  • этот метод может выполнять некоторые basic инструкции (математика, назначение локальных переменных,ifs, петли...).

я просматривал аннотации, и, похоже, нет ничего близкого к этому.
Мои варианты до сих пор:

  1. определите некоторую аннотацию,@SafeAnnotation, и применить его к методу, определяющему контракт с исполнителем, что он будет следовать установленным правилам, иначе система будет неисправность.

  2. определение Enum С разрешенными операциями. Вместо предоставления разрешенных методов предоставляется только метод, который принимает список этих объектов перечисления (или что-то подобное График Потока Управления?) и выполняет его, давая мне контроль над тем, что можно сделать.

пример:

public enum AllowedOperations { OP1, OP2 }

public class TheOneKnown {
    public void executeMyStuff (List<AllowedOperations> ops) {
        // ...
    }
}

У Меня Вопрос

есть ли какие-либо функции на языке, такие как аннотации, отражение или иное, позволяющее мне проверять (во время компиляции или во время выполнения), является ли метод допустимым (ie, удовлетворяет мои ограничения)?
Или, скорее, есть ли способ заставить его вызывать только ограниченный набор других методов?

если нет (и я думаю, что нет), будет ли этот второй подход подходящей альтернативой?
Подходит, как в интуитивном, хорошо продуманном и / или хорошей практике.

Обновления (Прогресса)

посмотрев на некоторых связанных с этим вопросах я также рассматриваю (в качестве третьего варианта, возможно) следующие шаги, приведенные в принятом ответе этот вопрос. Хотя, это может потребовать некоторого переосмысления архитектуры.

вся идея использования аннотаций для наложения ограничений, похоже, требует реализации моего собственного процессора аннотаций. Если это правда, я мог бы также рассмотреть небольшой доменный язык, чтобы программист использовал эти ограниченные операции, позже перевод кода на Java. Таким образом, я также буду иметь контроль над тем, что указано.

5 ответов


Я думаю, что направление в этом вопросе - это хорошо.

  • используйте определенный ClassLoader lo загрузите класс. Остерегайтесь, что они интересный тип лошади, обычно бывает, что сам класс загружается родительским загрузчиком классов. Вероятно, вы хотите какой-то urlclassloader, на, и родительский загрузчик классов будет установлен в корневой загрузчик классов, хотя этого недостаточно.
  • использовать threads чтобы избежать зацикливания (а реализация Runnable чем расширение Thread, как там) - это может быть ненужным, если вы не беспокоитесь об этом.
  • используйте SecurityManager, чтобы избежать java.io операции

в дополнение к вышесказанному, я рекомендую 2 варианта:

дайте метод a контроллер, который будет содержать функции, которые она может вызвать

например:

public void foo(Controller ctrl) {
}

public class Controller {
   public boolean commit();
   public boolean rollback();
}

это может дать пользователю, какие операции разрешены.

использовать Intent-как команда шаблон

в Android компоненты системы довольно закрыты. Они не могут напрямую общаться друг с другом, они могут только запустить событие, что "это произошло" или "я хочу это сделать".

таким образом, набор используемых команд не ограничен. Обычно, если методы делают только логику малого бизнеса, этого достаточно.


посмотрите на файлы политики java. Я не использовал их, и я не уверен, что они точно соответствуют вашей проблеме, но с некоторыми копаниями в документах они могут быть подходящими. Вот пара вопросов, которые могут помочь

ограничение доступа к файлам в Java

что такое простая политика безопасности Java для ограничения записи файлов в один каталог?

и вот некоторые документы по политике файл.

http://docs.oracle.com/javase/6/docs/technotes/guides/security/PolicyFiles.html


вы можете ограничить классы, используемые ненадежным кодом с помощью пользовательского загрузчика классов:

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.";
    }
}

запуск этого приведет к

I am good
Exception in thread "main" java.lang.NoClassDefFoundError: java/lang/Thread
    at tools.sandbox.Evil.toString(Evil.java:7)
    at tools.sandbox.Sandboxer.main(Sandboxer.java:18)
Caused by: java.lang.ClassNotFoundException: java.lang.Thread
    at java.net.URLClassLoader.run(URLClassLoader.java:366)
    at java.net.URLClassLoader.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
    ... 2 more

конечно, это предполагает уход с занятия вы белый список. Он также не может предотвратить отказ в обслуживании, такие как

while (true) {}

или

new long[1000000000];

другой альтернативой будет использование En embedded script interpreter, например groovy one (http://groovy.codehaus.org/Embedding + Groovy) и оценить содержимое сторонних методов во время выполнения с предварительной проверкой выполнения.

преимущество заключается в том, что вы сможете ограничить доступ только к переменным, которые вы свяжете для выполнения скрипта.

вы также можете написать свой собственный dsl проверки и применить его, например, используя пользовательскую аннотацию, к методу, который будет выполнять скрипт.


есть несколько оформление по договору библиотеки для Java, но я не могу рекомендовать одну в частности. Проверка Аргументов Java кажется легким решением, но опять же, у меня нет первых рук опыт работы с ним.