# Mehrere Objekte einer Bean



## pusteblume (16. Dez 2008)

Hallöchen,

ich habe eine Verständnisfrage: 

schicke ich ein jsp-formular ab, wird ja über die Action das ActionForm Bean2 mit den Eingaben aus dem Formular gefüllt. 
Bsp: Formular hat Name und ID. Mein ActionForm entsprechend auch. So wird jetzt der submit-Button geklickt, dann wird doch ein neues Objekt der Bean2 (ActionForm) angelegt und die properties Name und ID entsprechend gesetzt. Und wie ist das jetzt, wenn ich mehrere Objekte habe? 

Also es ist so, dass ich ein logic-iterate über eine Collection durchführe, in der Objekte vom Typ einer bestimmten Bean1 sind. Für jedes Objekt aus dieser Bean1 wird auf meiner JSP ein Eingabe-Formular generiert. Mit Submit sende ich dann alle Eingaben los. Wird jetzt für jedes Objekt ein eigenes Bean-Objekt des Types der Bean2 angelegt oder werden dann bspw. in Name alle Namen der Objekte gespeichert? 

Ähm, ich hoffe, das war verständlich genug ausgedrückt, wie ich das meine? *am-kopf-kratz*

Vielen Dank für Erklärungen!

LG pusteblume


----------



## gex (16. Dez 2008)

Struts? oder wovon sprichst du?


----------



## bronks (17. Dez 2008)

pusteblume hat gesagt.:
			
		

> ... Ähm, ich hoffe, das war verständlich genug ausgedrückt, wie ich das meine? *am-kopf-kratz* ...


Klar!  Da können keine Missverständnisse auftreten. Siehe u.g. Code und beachte das enthaltene Zauberwort "indexed". Die FormBean muss dafür etwas erweitert werden, aber da empfehle ich Dir die Internetsuche mit den Suchbegriffen "struts indexed"

Viel Erfolg!


```
<logic:present name="dasForm" property="dasList">
            <logic:iterate id="das" name="dasForm" property="dasList">
                <tr>
                    <td <html:text name="das" property="nb4" indexed="true"/></td>
                </tr>
            </logic:iterate>
        </logic:present>
```


----------



## pusteblume (17. Dez 2008)

@gex: japp, von Struts. sorry, dass ich vergaß, dies zu erwähnen. 

@bronks: besten Dank für deine Antwort. Ich hab folgende JSP:


```
<logic:empty name="BeanCollection" property="list">No allLayers available</logic:empty>
    <logic:iterate name="BeanCollection" property="list" id="BeanObj">
        <html:checkbox name="BeanObj" property="checked" value="${BeanObj.id}" indexed="true"/>
        <bean:write name="BeanObj" property="name" />
        

    </logic:iterate> <html:submit value="Save" />
```

und erhalte dann daraus diesen Code im HTML:


```
<form name="BeanCollection" method="post" action="/action.do">
    <table>
         <tr><td><input type="checkbox" name="BeanObj[0].checked" value="2" checked="checked">
            checkbox1

            <input type="checkbox" name="BeanObj[1].checked" value="3" checked="checked">
            checkbox2
        </td></tr>
```



> name="BeanObj[0].checked



Zeigt mir jetzt also an, dass ich ein Objekt vom Typ BeanObj (meine Bean) habe mit dem Index "0", oder? Aber mir ist jetzt nicht so klar, wie ich an diese Objekte rankomme. Meine Action sieht so aus:


```
public class LayerMgmtAction extends Action {
public ActionForward execute(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		
		BeanCollection beanCollection = (BeanCollection)form;
		ArrayList checklist = beanCollection.getListe();
                                ...
		}
```

Aber in der Liste ist nichts drinn. Auf der Konsole erhalte ich die Anzeige: 





> package.beans.BeanCollection@148b272


Das heißt ja also, dass es ein Objekt aus meiner ActionForm BeanCollection gibt, das aber nur leere Listen beinhaltet.  Wenn ich jetzt mit beanCollection.getListe().size() mir die Länge meiner Liste angeben lasse, so ist diese 0. Und wo sind jetzt die Objekte hin, die da oben in der HTML-Datei indiziert sind? 

Zur Vollständigkeit:

```
public class BeanCollection extends ActionForm {
	
	private ArrayList liste = new ArrayList();
	
	public ArrayList getListe() {
		returnliste;
	}
	public void setListe(ArrayList liste) {
		this.liste= liste;
	}
	public void reset(ActionMapping arg0, HttpServletRequest arg1) {
		liste = new ArrayList();
	}
	
	
}
```

Ich habe auch oft gelesen, dass man mit einem request.getParamterValues("parameter") sich die Werte holen kann, aber das entspricht erstens nicht dem Struts-Konzept (wenn ich das denn richtig verstanden habe, nämlich dass das Actionform ja dazu da ist, den Request so auseinanderzuklamüsern, dass man dann die Objekte schon hat) und zweitens fehlt mir dann die Zuordnung der Parameter zu einander, weil ich ja keine wirklichen Bean-Objekte bekomme sondern nur String-Arrays... 

Ich habe wie empfohlen nach "struts indexed" gegoogelt. Aber alles, was ich dazu fand, war irgendwie nicht so erfolgsversprechend. In der Doku von Struts habe ich nun noch gefunden, dass man im ActionForm noch ein Array vom Typ meiner BeanObj anlegt. Aber trotzdem verstehe ich nicht, erstens wie ich die Objekte aus dem Formular da rein bekomme und zweitens wieder auslesen kann. Ich steh total auf'm Schlauch... 

Dies hier soll man wohl noch in das ActionForm implementieren. Was ich auch getan habe. Aber nun nicht weiter weiß. Wo bekomme ich denn jetzt den index her für set

```
private BeanObj [] beanObj= new BeanObj[] {new BeanObj(), new BeanObj(), new BeanObj()};

public BeanObj getBeanObj(int index) {
		return BeanObj[index];
	}
	
	public void setBeanObj(int index, BeanObj var) {
		this.lBeanObj[index]=var;
	}
```


Und dann wird gesagt, dass ich nun mit 



> <html:text property="BeanObj[1].checked" />



das erste Element aus dem Array verwenden kann. Und wie geht das jetzt quasi umgekehrt? 

Für jede weitere Anregung bin ich sehr sehr dankbar!


----------



## HLX (17. Dez 2008)

So sollte es gehen:

```
<logic:empty name="BeanCollection" property="meineListe">No allLayers available</logic:empty>
    <logic:iterate name="BeanCollection" property="meineListe" id="meineListe">
        <html:checkbox name="meineListe" property="checked" value="${meineListe.id}" indexed="true"/>
        <bean:write name="meineListe" property="name" />
        

    </logic:iterate> <html:submit value="Save" />
```


```
public class BeanCollection extends ActionForm {
	
    // DIESES ATTRIBUT MUSS GENAUSO HEISSEN WIE DAS PROPERTY-ATTRIBUT IM <logic:iterate>-TAG,
    // DENN PROPERTY-ATTRIBUTE IN STRUTS-TAGS GREIFEN IMMER AUF DIE BEZEICHNUNG VON BEAN-ATTRIBUTEN ZU!
    private ArrayList meineListe; 	

    // GETTER
    public ArrayList getMeineListe() {
            return meineListe;
    }

    // SETTER
    public void setMeineListe(ArrayList liste) {
        this.meineListe = liste;
        }
    }

    public void reset(ActionMapping arg0, HttpServletRequest arg1) {
        meineListe = new ArrayList();
    }
}
```


----------



## pusteblume (17. Dez 2008)

hallo hlx,

das habe ich soweit so eingehalten. Und trotzdem ist die Liste aus meiner Collection-Bean leer.  

Muss ich vielleicht noch irgendwo in der struts-config.xml irgendwas einstellen? 


```
<form-bean name="BeanObj" type="package.beans.BeanObj" />
<form-bean name="BeanCollection" type="package.beans.BeanCollection" />

<action
    path="/action"
    type="package.actions.Action"
    name="BeanCollection"
    validate="false"
    input="/inputForm.jsp">
    <forward name="param" path="/ParamForm.jsp" />
    <forward name="cancel" path="/userRegistration.jsp" />
</action>
```

EDIT:
woher weiß denn Struts eigentlich, dass in die BeanCollection.list BeanObj-Objekte reingehören? Öhm.. das wird ja irgendwie nirgendswo festgelegt, oder? Mit 


> value="${BeanObj.id}"


 wird ja nur ein int-Wert übergeben und mehr nicht. 

Ich glaub, ich hab grad nen Knoten in meiner Denke...  :bahnhof: 
Der logic:iterate holt sich ja aus meiner Bean BeanCollection die Liste liste, in der wiederum Objekte vom Typ BeanObj gespeichert sind. Für diese werden die Checkboxen gerendert. Die, bei denen dann die Checkbox checked ist, werden beim Submit übergeben, ja allerdings doch nur der Value=="${BeanObj.id}". Wo sollen denn da jetzt die BeanObj-Objekte herkommen? Das macht doch jetzt gar keinen Sinn, oder?? Muss ich da nicht eigentlich jetzt eine ActionForm schreiben, in die die id's der BeanObj-Objekte aus dem Formular reingepumpt werden, mit denen könnte ich ja dann ne DB-Abfrage à la "hole mir alle objekte aus der db mit den id's" machen, oder? 


Gruß + Danke,
pusteblume[/quote]


----------



## bronks (17. Dez 2008)

Ich hab Dir hier ein kleines Demo raufgeladen, welches alle Fragen klären sollte: http://www.java-forum.org/de/userfiles/user2415/StrutsIndexedProperties.zip


----------



## HLX (18. Dez 2008)

pusteblume hat gesagt.:
			
		

> Muss ich vielleicht noch irgendwo in der struts-config.xml irgendwas einstellen?
> 
> ```
> <form-bean name="BeanObj" type="package.beans.BeanObj" />
> ```


Nein, dass hat damit nichts zu tun. Die o.g. Form-Bean-Deklaration kann aber weg. BeanObj ist wohl kein Formular.



			
				pusteblume hat gesagt.:
			
		

> EDIT:
> woher weiß denn Struts eigentlich, dass in die BeanCollection.list BeanObj-Objekte reingehören? Öhm.. das wird ja irgendwie nirgendswo festgelegt, oder? Mit
> 
> 
> ...


Struts interessiert sich nicht für den Objekttyp. Es behandelt deine ActionForm als Bean und ruft per Reflection zu den Property-Attributen eines Tags die entsprechenden Methoden am Objekt auf. Von daher ist es wichtig, übereinstimmende Bezeichnungen zu haben. Falls eine Methode nicht vorhanden ist, oder einen falschen Typ hat bekommst du eine Exception.



			
				pusteblume hat gesagt.:
			
		

> Der logic:iterate holt sich ja aus meiner Bean BeanCollection die Liste liste, in der wiederum Objekte vom Typ BeanObj gespeichert sind. Für diese werden die Checkboxen gerendert. Die, bei denen dann die Checkbox checked ist, werden beim Submit übergeben, ja allerdings doch nur der Value=="${BeanObj.id}". Wo sollen denn da jetzt die BeanObj-Objekte herkommen? Das macht doch jetzt gar keinen Sinn, oder??



Stimmt, das Value-Attribut ist auch völliger quatsch. Das kann weg:

```
<html:checkbox name="meineListe" property="checked" indexed="true"/>
```
Diese Angabe bewirkt, eine Bindung zwischen der checked-Variable in deinem Bean-Objekt und dem Checkboxfeld. Dein Bean-Klasse sieht idealerweise so aus:

```
public class BeanObj {

    private boolean checked; // auch hier wieder der Name aus dem Struts-Tag!

    // hier noch die getter und setter
}
```


----------



## pusteblume (4. Feb 2009)

hallo bronks,

ich habe mir dein hochgeladenes beispiel mal zu gemüte geführt und es versucht, auf meine anwendung umzubauen. aber wenn ich mir die liste meiner collection holen möchte, dann bekomme ich eine nullpointer-exception. wenn ich mir dann einfach mal die liste als objekt auf der konsole ausgeben lasse, zeigt es mir null an, sprich da is nix. 

also back to the roots habe ich dein beispiel genauso kopiert und ausgeführt und es passiert genau das selbe:

an der stelle


```
Iterator it = personList.iterator();
```

wird die nullpointerexception geworfen. davor habe ich ein debug mal auf der konsole ausgeben lassen:



```
logger.debug("personList="+personList);
```

mit dem ergebnis:



> [DEBUG] - WelcomeAction.java:49:
> personList=null



woran liegt das jetzt? 

ich poste jetzt mal ganz dreist den gesamt trace. vielleicht fällt jemandem etwas auf?! 



> javax.servlet.ServletException: java.lang.NullPointerException
> org.apache.struts.chain.ComposableRequestProcessor.process(ComposableRequestProcessor.java:286)
> org.apache.struts.action.ActionServlet.process(ActionServlet.java:1913)
> org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:462)
> ...



ich versteh es nicht. vorallem, was ich bisher auch noch nicht verstanden habe, ist folgendes: benutzt man *indexed="true"* dann erhält man ja in der HTML-Ausgabe soetwas:

<input type="hidden" name="Person[0].name" value="pusteblume">

etc...

Wie komme ich an das Person[0].name bzw pusteblume ran? in meinem anwendungsfall wäre es so, dass ich mir von person alle properties ausgeben lasse, die verändert werden dürfen und ich die veränderungen dann speichern möchte. ich meine irgendwo muss doch da ein array vom typ "Person" rumschwirren, in dem dann die objekte gespeichert sind. oder nicht? und wo ist das? ich bin mal wieder total ratlos...  :cry:  ???:L  :bahnhof: 

Für jeden Tipp wär ich sehr dankbar!!! 

LG pusteblume


----------



## HLX (5. Feb 2009)

pusteblume hat gesagt.:
			
		

> an der stelle
> 
> 
> ```
> ...


Das liegt daran, dass das Formular nur im Request-Scope verfügbar ist. Dadurch ist bei jeder Anfrage die Personenliste nicht initialisiert. Beim Submit läufst du dann in eine NullPointerException. Ändere in der struts-config.xml das Action-Mapping und setze den scope auf "session".



			
				Pusteblume hat gesagt.:
			
		

> Wie komme ich an das Person[0].name bzw pusteblume ran? in meinem anwendungsfall wäre es so, dass ich mir von person alle properties ausgeben lasse, die verändert werden dürfen und ich die veränderungen dann speichern möchte. ich meine irgendwo muss doch da ein array vom typ "Person" rumschwirren, in dem dann die objekte gespeichert sind. oder nicht? und wo ist das? ich bin mal wieder total ratlos...  :cry:  ???:L  :bahnhof:


Es gibt kein zusätzliches Array. Struts greift tatsächlich auf die Liste personList in der ActionForm zu. Dies wird über die Methode get*Person(index)* in der Formularklasse geregelt. Indexed=true kann in Struts sowohl auf Arrays als auch auf Objekte vom Typ Collection angewandt werden. Du kannst auch folgendes machen:

```
<logic:iterate id="personList" name="WelcomeForm" property="personList">
          <html:text name="personList" property="name" indexed="true"/>
```
Wenn du die Bezeichnung der Formularvariable auch in die *id* des Iterate-Tag schreibst greifst du ebenfalls direkt auf die variable zu (in diesem Fall 'personList'). Dann kannst du dir die Methode getPerson sparen - Struts regelt für dich den Zugriff auf das korrekte Objekt in der Liste.


----------



## pusteblume (11. Feb 2009)

Hallo HLX,

das Problem konnte nun wie folgt gelöst werden:

In der Klasse mit der Liste gibt es nur die get- und set-Methode für die ArrayList und die reset-Methode. Und in der Action wird der request so gesetzt:


```
request.getSession().setAttribute("name", collection);
```

So funzt es einwandfrei. Verstehen tu ich das allerdings noch nicht so hundertprozentig. Mit der Angabe scope="session" hat es nicht geklappt. Warum auch immer... irgendwie geht da irgendwo unterwegs etwas verloren. 

Trotzdem vielen Dank für die Hilfestellungen!!!

LG pusteblume


----------

