2011-03-30 3 views
8

Je me demande quel est le meilleur moyen de récupérer des propriétés imbriquées dans Groovy, en prenant un objet donné et arbitraire "propriété" String. Je voudrais quelque chose comme ceci:comment récupérer des propriétés imbriquées dans groovy

someGroovyObject.getProperty("property1.property2") 

J'ai eu du mal à trouver un exemple d'autres qui veulent faire cela, alors peut-être je ne comprends pas un concept Groovy de base. Il semble qu'il doit y avoir un moyen élégant de le faire.

Comme référence, il est une caractéristique de Wicket qui est exactement ce que je cherche, appelé PropertyResolver: http://wicket.apache.org/apidocs/1.4/org/apache/wicket/util/lang/PropertyResolver.html

Les conseils seraient appréciés!

Répondre

22

Je ne sais pas si Groovy a une façon intégrée de faire cela, mais voici 2 solutions. Exécutez ce code dans le Groovy Console pour le tester.

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') 
+0

C'est plus ou moins ce que je fais maintenant, mais votre chemin est plus propre! –

+0

désolé, Don, aurait dû accepter votre réponse il y a longtemps (à l'époque où je ne savais pas ce que je faisais sur ce site). merci ... –

+0

Note: J'ai testé ces dans une sorte, et Eval était beaucoup plus lent que la version tokenized sur mon système. –

2

Groovy Beans vous permet d'accéder directement aux champs. Vous n'avez pas besoin de définir les méthodes getter/setter. Ils sont générés pour vous. Chaque fois que vous accédez à une propriété bean, la méthode getter/setter est appelée en interne. Vous pouvez contourner ce problème en utilisant l'opérateur. @. Voir l'exemple suivant:

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) 

Si vous ne traitez pas avec des collections, vous pouvez tout simplement appeler le champ que vous souhaitez accéder.

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

Si vous souhaitez accéder à un champ dans une collection, vous devez sélectionner l'élément:

assert 'BOA' == person.accounts[0].bankName 
assert 300 == person.accounts[1].balance​​​​​​​​​ 
+1

C'est un bon conseil, mais je veux être en mesure de prendre une chaîne. Y a-t-il un moyen pour que force _person. "Adresse.street" _ retourne la valeur de _person.address.street_? –

+0

Vous pouvez utiliser [l'invocation de méthode dynamique de Groovy] (http://groovy.codehaus.org/Dynamic+Groovy). Cependant, cela nécessite que vous déclariez le nom de la méthode: person. "GetAddress"(). "GetStreet"(). –

+0

merci pour l'info et le lien ... je vais lire à ce sujet et voir si cela peut aider ici. –

1

Vous pouvez également utiliser propertyMissing C'est ce que vous pourriez appeler la méthode intégrée de Groovy.

dans votre Declare classe:

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

Reportez-vous ensuite à vos propriétés selon vos besoins:

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

Ceci est automatiquement récursive, et vous ne devez pas appeler explicitement une méthode. C'est seulement un getter, mais vous pouvez aussi définir une seconde version avec des paramètres pour faire un setter. L'inconvénient est que, pour autant que je sache, vous ne pouvez définir qu'une seule version de propertyMissing, vous devez donc décider si la navigation par chemin dynamique est ce que vous voulez l'utiliser.

Questions connexes