Доступ к значению атрибута объекта с помощью выражения - PullRequest
2 голосов
/ 27 апреля 2009

Рассмотрим следующий код:

Class Demo
{
    Person person = new Person("foo"); // assume Person class has a 'name' field.

    //Now, how do I get the value of a field, using some expression.
    String expression = "person.name";
}

Теперь я хочу оценить выражение, чтобы получить значение атрибута name. Кто-нибудь может подсказать, как это можно сделать?

- Обновлено: строка 'expression' Я получу ее из файла XML. Так можно ли будет использовать «Отражение» и в этом сценарии? строка 'expression' может также входить в более глубокие уровни, например 'person.birthday.date'.

Ответы [ 11 ]

3 голосов
/ 27 апреля 2009

В Java нет собственного способа сделать это. Существует множество других вариантов.

Один из подходов заключается в использовании JXPath . Это использует синтаксис в стиле XPath для запроса объектов. Это может быть немного излишним для ваших целей, но, несомненно, мощным.

например. с домашней страницы JXPath:

Address address = (Address)JXPathContext.newContext(vendor).
         getValue("locations[address/zipCode='90210']/address");

, который запрашивает у данного объекта вендора его адрес с почтовым индексом 90210. Таким образом, вы можете перемещаться по иерархиям объектов и предоставлять предикаты для выполнения запросов типа «SELECT .. WHERE».

См. Также эту статью java.net для большего количества примеров (бесстыдный плагин того, что я написал).

2 голосов
/ 27 апреля 2009

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

Тем не менее, в вашем вопросе есть что-то, что беспокоит меня, что ваша проблема больше связана с дизайном, чем с отражением. Можете ли вы рассказать нам больше?

1 голос
/ 27 апреля 2009

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

Но, если ваши выражения простые , вы можете сделать что-то вроде этого:

public static Object GetFieldValue(Object obj, String expr) throws SecurityException, NoSuchFieldException, IllegalAccessException {
    if (obj == null)
        throw new IllegalArgumentException("obj");

    if (expr == null || expr.isEmpty())
        throw new IllegalArgumentException("expr");

    String[] parts = expr.split("\\.");

    if (parts.length > 0) {
        Object currentFieldValue = obj;

        for (String fieldName : parts) {
            Field field = currentFieldValue.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            currentFieldValue = field.get(currentFieldValue);
        }

        return currentFieldValue;
    }

    return null;
}
1 голос
/ 27 апреля 2009

Вы, конечно, могли бы делать такие вещи самостоятельно, написав анализатор, владеющий отражениями, но вы также можете использовать язык оценки Expresion Spring, который почти соответствует вашим ожиданиям ( Документация !).

Вы можете сделать несколько классных вещей с ним; это мощный язык, который похож на EL-скрипт JSP (который также является опцией). Вам просто нужно передать контекст, в котором «человек» что-то значит.

Пример!

public class DoStuff {
  class MyVariables {
    private person;
    public void getPerson() { return person; }
    public void setPerson(Person person) { this.person = person; 
  }

  public static Object eval( String input ) {
     MyVariables myVariables = new MyVariables();
     StandardEvaluationContext simpleContext = new StandardEvaluationContext(myVariables);
     ExpressionParser parser = new SpelAntlrExpressionParser();
     Expression exp = parser.parseExpression( input );
     return exp.getValue(context);
  }

  public static void main(String[] args) {
      String name = (String)eval("person.name");//woot!
  }

}
0 голосов
/ 27 апреля 2009

Не делайте такой тяжелой работы самостоятельно. Используйте библиотеку, которая делает это. Утилиты bean-компонентов Apache имеют метод BeanUtils.getProperty (Object bean, String name), которому вы можете передать свой bean-компонент и свойство. Например, BeanUtils.getProperty (foo, «name») получит вам свойство name персоны foo (вы не будете использовать «person.name», потому что это будет эквивалентно foo.getPerson (). GetName () ).

Вы можете скачать jar BeanUtils из центрального хранилища maven: http://repo1.maven.org/maven2/commons-beanutils/commons-beanutils/1.8.0/commons-beanutils-1.8.0.jar

Может потребоваться наличие некоторых зависимостей в иерархии http://repo1.maven.org/maven2/commons-beanutils, я не уверен. Вы можете найти jar Apache Commons BeanUtils jar и посмотреть, сможете ли вы получить зависимости таким образом, но вы можете использовать jar как отдельный файл.

0 голосов
/ 27 апреля 2009

Действительно ли вам НУЖНО "Имя", чтобы быть членом Java-объекта? Можете ли вы сохранить его в хеш-таблице и использовать вместо этого поиск?

(Подсказка: вам НУЖНО, чтобы он был членом объекта, если вы выполняете над ним операции внутри этого объекта, и даже тогда у вас есть объект, который хранит свои данные внутри как хеш, если вы этого хотите) *

0 голосов
/ 27 апреля 2009

Если данные представляют собой XML DOM, то, вероятно, лучшим вариантом будет XPath . Если вы хотите добавить собственную поддержку Unified Expression Language , вы можете добавить его, реализовав несколько классов . Если вы хотите использовать практически любой язык сценариев через javax.script (требуется Java 6), посмотрите эту библиотеку механизмов сценариев .

Из коробки вы можете сделать это с помощью Java 6:

public class ResolveMe {

  public URI uri;

  public static void main(String[] args)
      throws ScriptException, URISyntaxException {
    ResolveMe myObject = new ResolveMe();
    myObject.uri = new URI("http://stackoverflow.com/foo");

    String expression = "myObject.uri.host";

    ScriptEngineManager sem = new ScriptEngineManager();
    ScriptEngine engine = sem
        .getEngineByMimeType("application/javascript");
    engine.put("myObject", myObject);

    System.out.println(engine.eval(expression));
  }

}
0 голосов
/ 27 апреля 2009

Если вы хотите, чтобы пользователи могли настраивать вашу программу путем предоставления выражений (например, вашего выражения person.name), вы можете посмотреть на внедрение groovy или jython в вашу программу и запуск их выражений в этом контексте. Вот первый хит Google для встраивания Groovy. http://groovy.codehaus.org/Embedding+Groovy

0 голосов
/ 27 апреля 2009

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

Почему вы хотите, чтобы какой-то текст интерпретировался? Вы намеренно пишете переводчика? Должна ли ссылка на person действительно рассматриваться как объект сам по себе? Сообщите нам свое намерение.

0 голосов
/ 27 апреля 2009

«Правильный» способ состоит в том, чтобы в Person получить метод get с именем getName (), который возвращает значение name.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...