2015-07-01 2 views
2

Учитывая этот класс:Использование Spring, как добавить элементы в окончательный, предварительно заполненный список?

public class Node { 
    private final List<Node> children; 
    public Node(){ 
    children = new ArrayList<>(); 
    // possibly pre-populate the list here 
    } 
    public List<Node> getChildren(){ 
    return children; 
    } 
} 

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

<bean id="node1" class="Node"> 
    <property name="children"> 
    <add-item><bean class="Node"/></add-item> <!--pseudocode--> 
    <add-item><bean class="Node"/></add-item> <!--pseudocode--> 
    </property> 
</bean> 

ответов я нашел в Spring IoC документов и форумы не удовлетворяли меня, потому что предлагаемые решения участвуют различные степени накладных расходов: Дополнительные боб картографирования, фабричные методы, абстрактные боб, чтобы наследовать от ... ISN» Там что-то более элегантное?

+0

возможно дубликат [Как определить список боб в Spring] (http://stackoverflow.com/ вопросы/2416056/how-to-define-a-list-bean-in-spring) – Timo

ответ

3

Я бы пошел с инжектированием списка непосредственно в конструктор. Это делает его не сложно Используйте последнее поле:

public class Node { 
    private final List<Node> children; 
    public Node(List<Node> children){ 
    this.children = children; 
    } 
    public List<Node> getChildren(){ 
    return children; 
    } 
} 

<bean id="node1" class="Node"> 
    <constructor-arg> 
     <list> 
      <item><bean class="Node"/></item> <!--pseudocode--> 
      ... 
     </list> 
    </constructor-arg>  
</beans> 

EDIT на ваш комментарий:

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

... 
public Node(List<Node> children){ 
    this.children = new ArrayList<>(); 
    // do some initialization before... 
    this.children.addAll(children); 
    // do some initialization after... 
} 
... 
+0

да, хороший ответ, однако, что, если бы у меня были предопределенные элементы в классе? (отредактировал мой пример, чтобы уточнить) – Markus

+0

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

1

Я изменил класс Node немного

public class Node implements InitializingBean{ 

private final List<Node> children; 

private String name; 

public Node() { 
    children = new ArrayList<>(); 
} 

@Override 
public void afterPropertiesSet() throws Exception { 
    //predefined nodes 
    Node node = new Node(); 
    node.setName(":)"); 
    children.add(node); 
} 

public String toString(){ return name; } 

public List<Node> getChildren() { 
    return children; 
} 

public void setNodes(Node nodes[]){ 
    if(nodes != null){ 
     for(Node node: nodes){ 
      this.children.add(node); 
     } 
    } 
} 

public void setChildren(Object something){ 
    System.out.println(something.getClass()); 
} 
public void setName(String name) { this.name = name; } 

}

Хитрость заключается в повторении значений аргументов и добавлении в предопределенный список массивов. Причина, по которой я назову ее setNodes, а не setChildren, потому что Spring будет изучать тип дочернего свойства от getChildren. Если я назвал установщика setChildren, я получу IllegalArgumentException.

Конечно, я могу использовать ArrayList вместо собственного массива, но вы сказали, что не хотите накладных расходов. Создание массива - ничего, добавление объектов из массива в ArrayList - это просто создание ссылки, которая тоже дешевая.

Это определение компонента

<bean id="node1" class="playground.Node"> 
    <property name="nodes"> 
     <array > 
      <bean class="playground.Node"> 
       <property name="name" value="A" /> 
      </bean> 
      <bean class="playground.Node"> 
       <property name="name" value="B" /> 
      </bean> 
     </array> 
    </property> 
</bean> 
+0

да, я также подумал об одном свойстве списка, читаемом, представляющем всех дочерних элементов и втором свойстве списка, доступном для записи , чтобы добавить детей. Он уверен, работает и не так уж плох, но по-прежнему чувствует себя как «адаптировать модель домена к возможностям Spring» вместо «использовать Spring для адаптации к модели домена» – Markus

+0

Если вы вообще не хотите изменять класс модели, вы должны использовать Spring java config вместо этого. Другим обходным решением является использование метода MethodInvokingFactoryBean', чтобы вызвать метод 'add', но он очень громоздкий и вовсе не изящный, если Spring XML не поддерживает цикл. – hussachai

1

Вы не указали, где дети приходит. В качестве второго варианта можно использовать @PostContruct метод, если вы не хотите, чтобы ввести список в contstructor:

public class Node { 
    private final List<Node> children; 
    public Node(){ 
    children = new ArrayList<>(); 
    } 
    public List<Node> getChildren(){ 
    return children; 
    } 

    @PostConstruct 
    public void init() { 
    // this method will Spring call after dependency injection is done. 
    children.add(...) 
    } 
Смежные вопросы