Java: динамические свойства - PullRequest
12 голосов
/ 07 февраля 2010

Дамы и господа,

Я новичок в Java, прости меня, если это очевидно, но я мало что об этом узнал.

Я хотел бы создать динамические свойства (переменные) для класса во время выполнения (определить объект, который можно изменить во время выполнения, добавив или изменив свойства и методы).


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

Python позволяет мне добавлять свойства во время выполнения. Groovy, кажется, позволяет это тоже. Единственное, что в «чистом» мире Java указывает на это, похоже, «Динамические прокси».

Но я пока не могу понять, справятся ли они с делом.

Ответы [ 5 ]

10 голосов
/ 07 февраля 2010

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

Редактировать: Хорошо, по-видимому, некоторые разъяснения в порядке. ОП особо упомянул GAE, над которым none из этих методов будет работать, но я упомяну их, поскольку некоторые, кажется, исключают их отсутствие.

API компилятора Java (Java 6+) позволяет компилировать классы Java во время выполнения. Технически вы можете написать исходный файл Java, чтобы он выглядел именно так, как вы хотите, скомпилировать и загрузить его.

Библиотеки байт-кода Java могут переписывать классы во время выполнения. Это используется такими библиотеками, как JPA (и другие). Вы можете изменить классы таким образом.

Однако OP ссылается на: а) в отношении работы над GAE и б) более подробно в порядке того, как Javascript позволяет изменять классы или конкретные экземпляры во время выполнения путем динамического добавления, удаления или изменения свойств. Java, конечно, этого не делает и, в частности, не использует GAE.

Вышеприведенное не является исключением из этого, так же как приведение класса к char * в C ++, так что вы можете читать приватные члены, не означает, что C ++ не имеет закрытых членов. По сути, вы обходите среду выполнения Java с обоими этими методами, даже если они являются частью Java.

2 голосов
/ 07 февраля 2010

Я не знаю, является ли это опцией для GAE (я не проверял ограничения) и подходит ли она для ваших нужд, но, возможно, взгляните на класс BeanGenerator от CGLIB (альтернатива уродливому DynaBean из BeanUtils ). Цитата «Смерть DynaBeans» (посмотрите на пост):

Не один, чтобы позволить мой CGLIB Золотой Молот впустую, я проверил в классе BeanGenerator в CVS. Вы используйте это так:

BeanGenerator bg = new BeanGenerator();
bg.addProperty("foo", Double.TYPE);
bg.addProperty("bar", String.class);
Object bean = bg.create();

Сгенерированный класс real JavaBean, что означает, что вы можете использовать стандартные бобовые утилиты. Это включает все классы в net.sf.cglib.beans пакет (BeanCopier, BeanMap и BulkBean). Сделайте свою часть, чтобы положить конец тирании DynaBeans!

2 голосов
/ 07 февраля 2010

Java не поддерживает это. Лучше всего хранить / управлять в каком-либо внешнем хранилище данных, к которому вы можете получить доступ из кода Java. В качестве базового и встроенного примера вы можете использовать API java.util.Properties, который загружается при каждом запросе, или кэшировать и перезагружать через определенные промежутки времени, или перезагружать программно. Затем вы можете сохранить пары ключ-значение в файле .properties, который вы просто поместите в путь к классам. Вот учебник Sun по теме .

Файл свойств может выглядеть как

key1=value1
key2=value2
key3=value3

Если вы поместите его в classpath, вы можете загрузить его как

Properties properties = new Properties();
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
properties.load(classLoader.getResourceAsStream("file.properties"));
String key1 = properties.getProperty("key1"); // value1

Другими альтернативами являются, например, файлы XML (доступ к которым можно получить с помощью любого API Java XML) или просто база данных (доступ к которой можно получить с помощью API JDBC).

1 голос
/ 14 февраля 2014

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

Map<Object, Object> properties = new HashMap<Object, Object>();
roperties.put("title", "The Italian Job");
roperties.put("dateOfRelease", "new GregorianCalendar(1969, 0, 1).getTime()");
Object movieBean = BeanCreator.createBeanFromMap(properties);
1 голос
/ 25 января 2011

Возможно использование динамических прокси. Это также возможно сделать на GAE.

Сначала создайте класс «SomeObject», который предоставляет методы для получения и установки значений свойств (т.е. getProperty (имя) и setProperty (имя, значение)).

Затем создайте интерфейс «PropertyModel», который содержит методы, которые вы хотели бы, чтобы ваши сгенерированные объекты имели.

Вызовите TransparentProxy.newInstance (someObjectInstance, MyPropertyModel.class), чтобы создать динамический прокси.

В результате Java расширит ваш объект someObjectInstance указанным интерфейсом (кстати, вы можете указать более одного). Когда вы вызываете метод для прокси-объекта, вызов метода будет перенаправлен на метод invoke (...), определенный ниже, вам нужно будет изменить этот код, чтобы он обрабатывал как методы получения, так и установки, а также включал некоторую обработку исключений и т.д. Но в целом именно так работают динамические прокси в Java.

public class TransparentProxy implements InvocationHandler
{
private final SomeObject someObject;

private TransparentProxy(SomeObject someObject)
{
    this.someObject = someObject;
}

public static Object newInstance(SomeObject someObject,
    Class<? extends PropertyModel> propertyModel)
{
    return Proxy.newProxyInstance(someObject.getClass().getClassLoader(),
        new Class[] { propertyModel }, new TransparentProxy(someObject));
}

public Object invoke(Object proxy, Method method, Object[] args)
    throws Throwable
{
    return this.someObject.getProperty(method.getName());
}
}
...