как получить вложенные свойства в Groovy - PullRequest
9 голосов
/ 30 марта 2011

Мне интересно, каков наилучший способ получения вложенных свойств в Groovy, принимая данный объект и произвольную строку "свойство".Я хотел бы что-то вроде этого:

someGroovyObject.getProperty("property1.property2")

Мне было трудно найти пример других, желающих сделать это, поэтому, возможно, я не понимаю какую-то базовую концепцию Groovy.Кажется, должен быть какой-то элегантный способ сделать это.

В качестве справки, в Wicket есть функция, которая именно то, что я ищу, называется PropertyResolver: http://wicket.apache.org/apidocs/1.4/org/apache/wicket/util/lang/PropertyResolver.html

Любые советы будут оценены!

Ответы [ 4 ]

24 голосов
/ 30 марта 2011

Я не знаю, есть ли у Groovy встроенный способ сделать это, но вот два решения.Запустите этот код в Groovy Console , чтобы проверить его.

def getProperty(object, String property) {

  property.tokenize('.').inject object, {obj, prop ->       
    obj[prop]
  }  
}

// Define some classes to use in the test
class Name {
  String first
  String second
}

class Person {
  Name name
}

// Create an object to use in the test
Person person = new Person(name: new Name(first: 'Joe', second: 'Bloggs'))

// Run the test
assert 'Joe' == getProperty(person, 'name.first')

/////////////////////////////////////////
// Alternative Implementation
/////////////////////////////////////////
def evalProperty(object, String property) {
  Eval.x(object, 'x.' + property)
}

// Test the alternative implementation
assert 'Bloggs' == evalProperty(person, 'name.second')
3 голосов
/ 30 марта 2011

Groovy Beans позволяет напрямую обращаться к полям. Вам не нужно определять методы получения / установки. Они генерируются для вас. Каждый раз, когда вы обращаетесь к свойству bean-компонента, метод getter / setter вызывается внутренне. Вы можете обойти это поведение, используя оператор. @. Смотрите следующий пример:

class Person {
    String name
    Address address
    List<Account> accounts = []
}

class Address {
    String street
    Integer zip
}

class Account {
    String bankName
    Long balance
}

def person = new Person(name: 'Richardson Heights', address: new Address(street: 'Baker Street', zip: 22222)) 
person.accounts << new Account(bankName: 'BOA', balance: 450)
person.accounts << new Account(bankName: 'CitiBank', balance: 300)

Если вы не имеете дело с коллекциями, вы можете просто вызвать поле, к которому хотите получить доступ.

assert 'Richardson Heights' == person.name
assert 'Baker Street' == person.address.street
assert 22222 == person.address.zip

Если вы хотите получить доступ к полю в коллекции, вы должны выбрать элемент:

assert 'BOA' == person.accounts[0].bankName
assert 300 == person.accounts[1].balance​​​​​​​​​
1 голос
/ 12 ноября 2014

Вы также можете использовать propertyMissing. Это то, что вы можете назвать встроенным методом Groovy.

Объявите это в своем классе:

def propertyMissing(String name) {
    if (name.contains(".")) {
        def (String propertyname, String subproperty) = name.tokenize(".")
        if (this.hasProperty(propertyname) && this."$propertyname".hasProperty(subproperty)) {
            return this."$propertyname"."$subproperty"
        }
    }
}

Затем обратитесь к вашим свойствам по желанию:

def properties = "property1.property2"
assert someGroovyObject."$properties" == someValue

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

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

0 голосов
/ 26 марта 2013

См.

https://stackoverflow.com/a/15632027/2015517

Используется синтаксис $ {}, который может использоваться как часть GString

...