# myFaces - SelectItem



## y0dA (3. Mrz 2008)

Hi!
Wie handhabt ihr SelectItems? Sprich wenn ihr ein Dropdown in der View habt, welches mit SelectItems dargestellt wird, was setzt ihr als value?


```
new SelectItem(Object value, String label)
```

Mein Problem:
Wenn ein Umlaut in meiner List von SelectItems als *value* gesetzt wird dann kann ich im Dropdown so oft  wie ich möchte diese Zeile auswählen - sie wird nicht angenommen! Also im *label* macht ein Umlaut keine Probleme aber im value.

mfg


----------



## maki (3. Mrz 2008)

Wieso sollte ein Value einen Umlaut enthalten?

Value ist ein Objekt, nicht nur ein doofer String.

Nachtzrag: Klar sind Strings auch Objekte, aber ich hoffe du verstehst worauf ich hinaus will.


----------



## y0dA (3. Mrz 2008)

maki hat gesagt.:
			
		

> Wieso sollte ein Value einen Umlaut enthalten?
> 
> Value ist ein Objekt, nicht nur ein doofer String.
> 
> Nachtzrag: Klar sind Strings auch Objekte, aber ich hoffe du verstehst worauf ich hinaus will.



Ja und mein Problem ist wenn value ein String ist, dass ich dann im Dropdown diesen Wert zwar setzen kann, beim nächsten submit oder refresh der Seite, der Wert aber nicht im Controller dieser jsp gesetzt wird. Sprich wenn der Wert kein Umlaut beinhaltet dann wird er gesetzt andernfalls wird die setter methode im Controller nicht angesprochen..


----------



## maki (3. Mrz 2008)

Könntest deinen eigenen Converter für Strings schreiben:

http://forum.java.sun.com/thread.jspa?threadID=740228&messageID=4257613


----------



## y0dA (3. Mrz 2008)

Wenn ich für *value* ein eigenes Objekt erstellt habe, welche bspw. ort, strasse,land und einen identifier als Klassenmember besitzt, muss ich hiefür dann einen eigenen Converter schreiben?

bsp:

```
for (PlanningPoint p : l) {
			geoStartDropDownList.add(new SelectItem(p, p.getIdentifier()));
		}
```
Hier befülle ich nun die Liste mit value = PlanningPoint Objekt und label eben ein Feld aus dieser Klasse.

Wenn ich das dann in der View wie folgt mache, bekomme ich (wohl klarerweise) eine Exception:

```
<h:selectOneMenu id="planGeoDropdown1"
				value="#{planningContrl.geoStartDropDownSelected}"
				styleClass="outputText"
				rendered="#{planningContrl.renderGeoDropDownStart}">
				<f:selectItems value="#{planningContrl.geoStartDropDownList}" />
			</h:selectOneMenu>
```


**EDIT**
Ich formuliere die Frage um, macht es Sinn komplexe Typen im SelectItem als value anzugeben? Oder sollte man die Objekte bspw in einer Map halten und den key der Map als value des SelectItems setzen?


----------



## maki (3. Mrz 2008)

> Ich formuliere die Frage um, macht es Sinn komplexe Typen im SelectItem als value anzugeben? O


Absolutes ja!



> Oder sollte man die Objekte bspw in einer Map halten und den key der Map als value des SelectItems setzen?


Nein!

Natürlich nur, wenn man die Möglichkeit hat, wenn die App schon Transfer Objekte braucht (zB weil man ohne Domain/Business Model arbeitet), hat man eben nur TOs.


----------



## y0dA (3. Mrz 2008)

maki hat gesagt.:
			
		

> > Ich formuliere die Frage um, macht es Sinn komplexe Typen im SelectItem als value anzugeben? O
> 
> 
> Absolutes ja!
> ...



Da ich bisher leider das Thema Converter komplett ignoriert habe, stellt sich mir die Frage wie ich einen Converter für so eine komplexe Klasse implementieren soll.


```
Object getAsObject(FacesContext, UIComponent, String)
```


```
String getAsString(FacesContext, UIComponent, Object)
```

Diese beiden Methoden gehören implementiert, nur finde ich kein Bsp welches mein Problem abdeckt, da bei den ganzen Bsp Convertern immer nur "simple" Typen konvertiert werden (String,boolean,enum).

Hast du vllt ein Bsp für mich?

Wie soll ich die Methode *getAsString* implementieren? Alle Klassenmember in einem String zurückliefern?


----------



## maki (3. Mrz 2008)

getAsString soll einen String zurückliefern, den du brauchst um das Objekt wieder herzustellen bzw. zu "converten".

Wenn die Entities mit einer Id hast, könnte man das hernehmen, dann mit der Id zB aus einer HashMap oder der DB das Objekt wiederholen, wobei ersteres performanter wäre.

Jaja ioch weiss, mein "Nein!" zu deiner Frage war übereilt


----------



## y0dA (3. Mrz 2008)

Aber ich könnte auch alle Klassenmember Werte in einen String packen und bspw mit "," aneinanderstöpseln und bei der Methode getAsObject den umgekehrten Weg verfolgen?

Möchte nicht unbedingt mittels einer id und einer map das ganze lösen - dann könnte ich mir nämlich auch den konverter sparen!

passt das so (meine Gedankengänge^^).


----------



## maki (3. Mrz 2008)

Solltest dich mehr mit Convertern beafssen, ganz wichtig in JSF.


----------



## y0dA (3. Mrz 2008)

Bin ja grad dabei!
Weiters sauge ich ja auch dein Wissen, obwohl du damit grade wieder geizt!


----------



## maki (3. Mrz 2008)

Tut mir leid wenn dass dein Eindruck ist.

Wie gesagt, getAsString gibt dir einen String, diesen bekommst du zurück, und must daraus dein Objekt machen.
Den String von getAsString solltest du nicht anzeigen, wird intern vom Converter verwendet, ist zB der "value" eines SelectItems, während nur das "label" angezeigt wird.

Möchte dir die üblichen "TelephoneNumber" Konverter Beispiele ersparen, gibnt aber auch genug Beispiele die es mit Enums zeigen.

Jedenfalls musst du genug infos in den String packen um daraus wieder das Objekt zu machen.

Code aus meinem aktuellen Projekt wird dir nix nutzen, weil noch ein riesen Framework aussenrum ist, das ich erstens selbst nicht ganz verstehe und zweitens auch nicht als empfehlenswert betrachte (manchmal würde ich Mitarbeiter ganz gerne zwingen opensource zu verwenden bevor man sein eigenes Süppchen kocht).


----------



## y0dA (3. Mrz 2008)

Na, war nur ein Scherz, da deine vorhergehende Antwort eine Frage nicht beantwortet hatte 

Ok, ich hab mir nun einen Konverter erstellt:

```
public class PlanningPointConverter implements Converter {

	//------------------------------------------------------------------------------------------------------------------
	// HELPER METHODS
	//------------------------------------------------------------------------------------------------------------------

	/**
	 * interface implementation
	 * @param context context
	 * @param component component
	 * @param value value
	 * @return <code>{@link #PlanningPoint</code> object
	 */
	public Object getAsObject(final FacesContext context, final  UIComponent component, final String value)
			throws ConverterException {
		if (value.isEmpty()) {
			return null;
		}
		PlanningPoint p = new PlanningPoint();
	    String [] pComps = StringUtility.split(value, " ");
	    p.setCountry(pComps[0]);
	    p.setLocation(pComps[1]);
	    p.setStreet(pComps[2]);
	    p.setPostCode(pComps[3]);
	    p.setHouseNumber(pComps[4]);
	    p.setIdentifier(pComps[5]);
	    return p;
	}	

	/**
	 * interface implementation
	 * @param context context
	 * @param component component
	 * @param value value
	 * @return <code>{@link #PlanningPoint</code> as string
	 */
	public String getAsString(final FacesContext context, final  UIComponent component, final Object value)
			throws ConverterException {
		if (value != null) {
			return ((PlanningPoint) value).toString();	
		} else {
			return null;
		}
	}
}
```

Nun der Konverter funktioniert auch, sprich die beiden Methoden liefern korrekte Werte. Mein Problem ist jetzt, dass ich diesen Konverter 2 mal innerhalb einer panelgrid benötige:

```
<h:panelGrid id="planningPG5" columns="2" border="1">
			<h:outputText value="#{labels.planStartDropdown}"
				styleClass="outputText"
				rendered="#{planningContrl.renderGeoDropDownStart}" />
			<h:selectOneMenu id="planGeoDropdown1"
				value="#{planningContrl.geoStartDropDownSelected}"
				converter="planningPointConverter" styleClass="outputText"
				rendered="#{planningContrl.renderGeoDropDownStart}">
				<f:selectItems value="#{planningContrl.geoStartDropDownList}" />
			</h:selectOneMenu>
			<h:outputText value="#{labels.planEndDropdown}"
				styleClass="outputText"
				rendered="#{planningContrl.renderGeoDropDownEnd}" />
			<h:selectOneMenu id="planGeoDropdown2"
				value="#{planningContrl.geoEndtDropDownSelected}"
				converter="planningPointConverter" styleClass="outputText"
				rendered="#{planningContrl.renderGeoDropDownEnd}">
				<f:selectItems value="#{planningContrl.geoEndDropDownList}" />
			</h:selectOneMenu>
		</h:panelGrid>
```

Und nun verhält sich das ganze so, dass wenn ich von einem der beiden DropDowns die Werte "hole" - mittels einen cmd button, dann reagiert meine Applikation nicht mehr, wenn ich beim anderen DropDown das gleiche machen möchte - es wird keine Methoden aufgerufen..


----------



## maki (3. Mrz 2008)

Bekommst du messages?
JSF Fehlersuche kann ganz schön zeitraubend sein.

Benutzt du schon "facestrace"? 
Wenn nein, wäre jetzt der richtige Moment:
http://facestrace.sourceforge.net/


----------



## y0dA (3. Mrz 2008)

Nein ich bekomme überhaupt keine Fehler - aber alle meine Buttons führen ihre Aktionen nicht mehr aus...

**EDIT**
gut, facetrace meint bei der Validation gibt es einen error:


```
subViewPlanning:fPlanning:planGeoDropdown1: Validierungsfehler: Wert ist keine gültige Auswahl
```


----------



## maki (3. Mrz 2008)

Was heisst schon Fehler? Gilt das auch für Messages?

Musst schon genauer sein.

Benutzt du Facestrace oder nicht?


----------



## y0dA (3. Mrz 2008)

ja ich benutze Facestrace und u.a. wird folgendes bei Facestrace ausgegeben:

```
ERROR MESSAGES
Component ID: subViewPlanning:fPlanning:planGeoDropdown1
Severity: ERROR
Message: subViewPlanning:fPlanning:planGeoDropdown1: Validierungsfehler: Wert ist keine gültige Auswahl
```

Und das ganze passiert erst wenn ich ein weiteres mal dasselbe dropdown befüllen möchte oder wenn ich das andere befüllen möchte - sprich beim 1. mal kann ich das dropdown befüllen ein weiteres mal geht es nicht.


Passt das überhaupt so:

```
<h:selectOneMenu id="planGeoDropdown1"
				value="#{planningContrl.geoStartDropDownSelected}"
				converter="planningPointConverter" styleClass="outputText"
				rendered="#{planningContrl.renderGeoDropDownStart}">
				<f:selectItems value="#{planningContrl.geoStartDropDownList}" />
			</h:selectOneMenu>
```
Sprich, gehört der converter so hinzugefügt  - muss ich eventuell mit 
	
	
	
	





```
<f:converter/>
```
 arbeiten?
faces.config:

```
<converter>
		<converter-id>planningPointConverter</converter-id>
		<converter-class>
			at.pcd.wam.gegenstandsbereich.tmcWeb.common.PlanningPointConverter
		</converter-class>
	</converter>
```


**EDIT**
Gut wenn ich es so mache:

```
<h:selectOneMenu id="planGeoDropdown1"
				value="#{planningContrl.geoStartDropDownSelected}"
				rendered="#{planningContrl.renderGeoDropDownStart}">
				<f:converter converterId="planningPointConverter" />
				<f:selectItems value="#{planningContrl.geoStartDropDownList}" />
			</h:selectOneMenu>
```
Bekomme ich folgende Exception:

```
javax.faces.FacesException: Exception while calling encodeEnd on component : {Component-Path : [Class: javax.faces.component.UIViewRoot,ViewId: /jsp/secure/main.jsp][Class: org.apache.myfaces.custom.div.Div,Id: mainDiv3][Class: javax.faces.component.UINamingContainer,Id: subViewPlanning][Class: javax.faces.component.html.HtmlForm,Id: fPlanning][Class: javax.faces.component.html.HtmlPanelGrid,Id: planningPG5]}
	at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:559)
	at javax.faces.component.UIComponent.encodeAll(UIComponent.java:250)
	at javax.faces.component.UIComponent.encodeAll(UIComponent.java:246)
	at javax.faces.component.UIComponent.encodeAll(UIComponent.java:246)
	at javax.faces.component.UIComponent.encodeAll(UIComponent.java:246)
	at javax.faces.component.UIComponent.encodeAll(UIComponent.java:246)
	at org.apache.myfaces.application.jsp.JspViewHandlerImpl.actuallyRenderView(JspViewHandlerImpl.java:423)
	at org.apache.myfaces.application.jsp.JspViewHandlerImpl.renderView(JspViewHandlerImpl.java:380)
	at org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.java:41)
	at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:140)
	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:152)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.myfaces.webapp.filter.ExtensionsFilter.doFilter(ExtensionsFilter.java:147)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
	at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
	at java.lang.Thread.run(Thread.java:619)
Caused by: javax.faces.FacesException: Exception while calling encodeEnd on component : {Component-Path : [Class: javax.faces.component.UIViewRoot,ViewId: /jsp/secure/main.jsp][Class: org.apache.myfaces.custom.div.Div,Id: mainDiv3][Class: javax.faces.component.UINamingContainer,Id: subViewPlanning][Class: javax.faces.component.html.HtmlForm,Id: fPlanning][Class: javax.faces.component.html.HtmlPanelGrid,Id: planningPG5][Class: javax.faces.component.html.HtmlSelectOneMenu,Id: planGeoDropdown1]}
	at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:559)
	at org.apache.myfaces.shared_impl.renderkit.RendererUtils.renderChild(RendererUtils.java:515)
	at org.apache.myfaces.shared_impl.renderkit.html.HtmlGridRendererBase.renderChildren(HtmlGridRendererBase.java:221)
	at org.apache.myfaces.shared_impl.renderkit.html.HtmlGridRendererBase.encodeEnd(HtmlGridRendererBase.java:102)
	at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:556)
	... 25 more
Caused by: java.lang.NullPointerException
	at org.apache.myfaces.taglib.core.DelegateConverter.getAsString(DelegateConverter.java:101)
	at org.apache.myfaces.shared_impl.renderkit.RendererUtils.getConvertedStringValue(RendererUtils.java:621)
	at org.apache.myfaces.shared_impl.renderkit.html.HtmlRendererUtils.getSubmittedOrSelectedValuesAsSet(HtmlRendererUtils.java:362)
	at org.apache.myfaces.shared_impl.renderkit.html.HtmlRendererUtils.internalRenderSelect(HtmlRendererUtils.java:337)
	at org.apache.myfaces.shared_impl.renderkit.html.HtmlRendererUtils.renderMenu(HtmlRendererUtils.java:288)
	at org.apache.myfaces.shared_impl.renderkit.html.HtmlMenuRendererBase.encodeEnd(HtmlMenuRendererBase.java:57)
	at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:556)
	... 29 more
```


----------



## maki (3. Mrz 2008)

Ist anscheinend doch keine so gute Idee null zurückzugeben wenn ein String bzw. Objekt erwartet wird


----------



## y0dA (3. Mrz 2008)

Wie meinen?

Wäre dir sehr dankbar, wenn du dich näher darüber ausläßt - sitz ich hier schon 2h an dem Problem..


Was soll ich machen wenn der Converter null bekommt - ich kann mir ja kein Objekt herzaubern. Abgesehen davon geht er beim debuggen nicht in die Verzweigung wo null zurückgegeben wird.


----------



## maki (3. Mrz 2008)

> Caused by: java.lang.NullPointerException
> at org.apache.myfaces.taglib.core.DelegateConverter.getAsString(DelegateConverter.java:101)


Anscheinend darf getAsString kein null zurückliefern.


----------



## y0dA (3. Mrz 2008)

maki hat gesagt.:
			
		

> > Caused by: java.lang.NullPointerException
> > at org.apache.myfaces.taglib.core.DelegateConverter.getAsString(DelegateConverter.java:101)
> 
> 
> Anscheinend darf getAsString kein null zurückliefern.



Tut es auch nicht!
Ich habe dort einen Debugpoint gesetzt - da läuft er nicht rein, weiters diese Stelle mit "" geschmückt anstatt mit null --> keine Änderung des Problems.

Passt denn mein Converter?

Hier nochmal die Klassen:

```
public class PlanningPoint {

	//------------------------------------------------------------------------------------------------------------------
    // FIELDS
    //------------------------------------------------------------------------------------------------------------------
	
	/** country */
	private String country;
	
	/** location */
	private String location;
	
	/** street */
	private String street;
	
	/** post code */	
	private String postCode;
		
	/** house number */
	private String houseNumber;
	
	/** identifier */
	private String identifier;
	
	//------------------------------------------------------------------------------------------------------------------
    // CONSTRUCTOR
    //------------------------------------------------------------------------------------------------------------------
	
	/**
	 * constructor
	 * @param country country
	 * @param location location
	 * @param street street
	 * @param postCode postCode
	 * @param houseNumber houseNumber
	 */
	public PlanningPoint(final String country, final String location, final String street,
			final String postCode, final String houseNumber) {
		super();
		this.country = country;
		this.location = location;
		this.street = street;
		this.postCode = postCode;
		this.houseNumber = houseNumber;
	}

	/**
	 * empty constructor
	 */
	public PlanningPoint() {
		// nothing to do
	}
	
	//------------------------------------------------------------------------------------------------------------------
    // HELPER METHODS
    //------------------------------------------------------------------------------------------------------------------
	
	/**
	 * returns a string representation of the object
	 * @return object as string
	 */
	public String toString() {
		return this.country + ";" + this.location + ";" + this.street + ";" + this.postCode + ";"
			+ this.houseNumber + ";" + this.identifier;
	}
	
	//------------------------------------------------------------------------------------------------------------------
    // GETTER / SETTER
    //------------------------------------------------------------------------------------------------------------------

	/**
	 * getter method
	 * @return the country
	 */
	public String getCountry() {
		return this.country;
	}

	/**
	 * setter method
	 * @param country the country to set
	 */
	public void setCountry(final String country) {
		this.country = country;
	}

	/**
	 * getter method
	 * @return the location
	 */
	public String getLocation() {
		return this.location;
	}

	/**
	 * setter method
	 * @param location the location to set
	 */
	public void setLocation(final String location) {
		this.location = location;
	}

	/**
	 * getter method
	 * @return the street
	 */
	public String getStreet() {
		return this.street;
	}

	/**
	 * setter method
	 * @param street the street to set
	 */
	public void setStreet(final String street) {
		this.street = street;
	}

	/**
	 * getter method
	 * @return the postCode
	 */
	public String getPostCode() {
		return this.postCode;
	}

	/**
	 * setter method
	 * @param postCode the postCode to set
	 */
	public void setPostCode(final String postCode) {
		this.postCode = postCode;
	}

	/**
	 * getter method
	 * @return the houseNumber
	 */
	public String getHouseNumber() {
		return this.houseNumber;
	}

	/**
	 * setter method
	 * @param houseNumber the houseNumber to set
	 */
	public void setHouseNumber(final String houseNumber) {
		this.houseNumber = houseNumber;
	}

	/**
	 * getter method
	 * @return the identifier
	 */
	public String getIdentifier() {
		return this.identifier;
	}

	/**
	 * setter method
	 * @param identifier the identifier to set
	 */
	public void setIdentifier(final String identifier) {
		this.identifier = identifier;
	}
}
```


```
public class PlanningPointConverter implements Converter {

	//------------------------------------------------------------------------------------------------------------------
	// HELPER METHODS
	//------------------------------------------------------------------------------------------------------------------

	/**
	 * interface implementation
	 * @param context context
	 * @param component component
	 * @param value value
	 * @return <code>{@link #PlanningPoint</code> object
	 */
	public Object getAsObject(final FacesContext context, final  UIComponent component, final String value)
			throws ConverterException {
		if (value.isEmpty()) {
			return null;
		}
		PlanningPoint p = new PlanningPoint();
	    String [] pComps = StringUtility.split(value, ";");
	    p.setCountry(pComps[0]);
	    p.setLocation(pComps[1]);
	    p.setStreet(pComps[2]);
	    p.setPostCode(pComps[3]);
	    p.setHouseNumber(pComps[4]);
	    p.setIdentifier(pComps[5]);
	    return p;
	}	

	/**
	 * interface implementation
	 * @param context context
	 * @param component component
	 * @param value value
	 * @return <code>{@link #PlanningPoint</code> as string
	 */
	public String getAsString(final FacesContext context, final  UIComponent component, final Object value)
			throws ConverterException {
		if (value != null) {
			return ((PlanningPoint) value).toString();	
		} else {
			return null;
		}
	}
```


```

```

Controller snippet

```
public List<SelectItem> getGeoStartDropDownList() {
		return this.geoStartDropDownList;
	}


	public void setGeoStartDropDownList(final List<SelectItem> geoStartDropDownList) {
		this.geoStartDropDownList = geoStartDropDownList;
	}

	public PlanningPoint getGeoStartDropDownSelected() {
		return this.geoStartDropDownSelected;
	}

	public void setGeoStartDropDownSelected(final PlanningPoint geoStartDropDownSelected) {
		this.geoStartDropDownSelected = geoStartDropDownSelected;
	}
```


----------



## maki (3. Mrz 2008)

Würde mich da jetzt ganz langsam rantasten, was passiert wenn getAsString immer "test" zurückgibt, ohne irgendetwas anderes zu machen?


----------



## y0dA (3. Mrz 2008)

Ich denke ich weiß schon wo das Problem liegt:
Also diese beiden *<h:selectOneMenu>* werden anfangs nicht gerenderd, erst wenn der User Eingaben gemacht hat und ich jene an ein Webservice geschickt habe werden diese gerenderd und der myFaces Lifecycle ist halt mal über cool und beim ersten mal, wo der converter aufgerufen wird, ist der *value* leer! Gibt es eine Möglichkeit das zu beheben?

**EDIT**
Ok, selbst wenn ich dem Konverter bei getAsString "test" zurückgeben lasse und bei getAsObject ein Dummy Objekt mit Werten, bekomme ich von facesstrace die error msg:

```
subViewPlanning:fPlanning:planGeoDropdown1: Validierungsfehler: Wert ist keine gültige Auswahl
```


----------



## y0dA (4. Mrz 2008)

Hier habe ich etwas interessantes zu meinem Problem gefunden: NABBLE-MYFACES-USER-FORUM

Auszug:
_
Ok, I think I figured out my problem. I'll summarize here in the hopes that this helps someone. I initially got the
solution half right, by implementing a Converter to convert between the String representation of an Employee and 
an Employee object. However, I was still failing during the validation phase even though I had implemented a "null" 
validator that always returned. The problem is that the UISelectOne class has a "validateValue" method that attempts 
to validate that the selected item is in fact contained within the UISelectItems list. It does this by essentially calling 
java.lang.Object.equals() on the selected object to compare it against items in the list. Even though all the data fields
within the Employee object instances were the same, they had different object references, and therefore were
deemed to be different. This ultimately led to a failure during validation. In order to solve this, I had to implement an 
equals method of my own in the Employee class that overrides the default java.lang.Object.equals method. This 
equals method compared the data fields within two Employee objects and declared them equal if all fields were equal.

To summarize, if you want to populate a UISelectOne control with a list of objects that are not simple Strings, you 
need to do two things; implement a Converter to go back and forth between String and Object, and override 
java.lang.Object.equals with your own equals implementation that compares the Object's data fields. Hope this helps
someone out there. Good luck finding this documented somewhere. 
_

Konklusio: Ich habe die hashCode() und equals(Object obj) Methode überschrieben und siehe da, es funktioniert!

Nun habe ich nur mehr ein Problem hierbei:
Wenn ich nun in weiterer Folge den aktuellen Wert des selectOneMenu ändere (sprich ich wähle aus dem Dropdown
einen anderen Wert als den Defaultvalue aus) und jenes Objekt besitzt in einem String einen Umlaut dann bekomme 
ich beim Converter (getAsObject) so einen String herein:

```
A;Stockerau;OberzÃ¶gersdorf;2000;;A-2000 Stockerau OberzÃ¶gersdorf (+++)
```

Wie kann ich das verhindern, denn somit bekomme ich wieder die Error Msg (Faces Trace):

```
subViewPlanning:fPlanning:planGeoDropdown1: Validierungsfehler: Wert ist keine gültige Auswahl
```


----------



## maki (4. Mrz 2008)

> Konklusio: Ich habe die hashCode() und equals(Object obj) Methode überschrieben und siehe da, es funktioniert!


 :toll: 

Sehr gut y0dA, und danke für's mitteilen der Lösung


----------



## y0dA (4. Mrz 2008)

Und kannst du mir bei dem Encoding Thema behilflich sein?


----------



## maki (4. Mrz 2008)

Ist er der PLanningPointConverter um den es geht?


----------



## y0dA (4. Mrz 2008)

Ja!
Also wie oben schon erwähnt, wenn ich den Wert im Dropdown geändert habe und die Seite "refreshed" wurde (warum auch immer: Button und dergleichen) und eben jener Wert einen Umlaut beinhaltete, bekam ich in jenem Converter die Umlaute nicht korrekt dargestellt.

Lösung:
In der jeweiligen JSP inkludieren:

```
<%@ page pageEncoding="UTF-8"%>
```

Somit haben wir dieses Thema beendet 

Eine Frage zu Convertern habe ich trotzdem noch:
Wann soll ich einen Converter benutzen(bei jedem Input Text etc)?


----------



## maki (4. Mrz 2008)

EInen Converter kannst du immer benutzen wenn zB der eingegebene Text noch formatiert/geändert werden muss.
JSF bietet Standard Converter für die meisten java Datentypen (String, Date, etc.pp.)

Oder: Wenn du ein komplexes Objekt in der View anzeigen möchtest, zB eigene Datentypen 

Konverter sind sehr sehr nützlich in JSF!


----------



## y0dA (4. Mrz 2008)

Ok und eine Frage noch dann bin ich fertig:
Wenn mein Converter bzw dessen Methoden die ConverterException werfen wo kann ich die abfangen? Ich selbst rufe den Converter ja nicht auf!?


----------



## maki (4. Mrz 2008)

Die Converter Exeption und die Validator Exception werden intern gefangen und als Messages weitergereicht.

Keine ERROR level logging, nur INFO level 

Deshalb ist FacesTrace so nützlich, kannst dir die messages anzeigen lassen ohne das message/s tag zu verwenden 

Ist dir klar warum Converter wichtig sind?
Stell dir vor du hast ein enum, in der Managedbean arbeitest du nur damit, bekommst von der String represetation nix mit!


----------



## y0dA (4. Mrz 2008)

Denke schon dass ich Converter nun verstanden habe, jedoch sehe ich im Moment bei meinem Projekt kein allzu großes Einsatzgebiet hierfür, ausser eben bei den Dropdowns, da ich hier in die SelectItems das ganze Objekt packen möchte.

Ja und wenn ich diese Converter Error Msg nun ausgeben möchte wo soll ich das machen? Sprich in der JSP gibt es ein <message for=...>

Ich werde ja nicht im Converter selbst mir die Komponente holen müssen und dann den Errortext setzen? Oder doch?

Also wie komme ich dazu die Msg auszugeben?


----------



## maki (4. Mrz 2008)

Es reicht das message tag zu verwenden, allerdings zeigt ein Message tag nur die messages für dies Komponente (for=..), das messages tag kann alle zeigen.


----------



## y0dA (4. Mrz 2008)

Also wenn ich in meinem Converter absichtlich (Testzweck) eine ConverterException werfe, dann bekomme ich keine Fehlermeldung sondern eine Fehlerseite mit dem tollen Stacktrace:

```
10:23:25,225 - ERROR javax.faces.webapp._ErrorPageWriter - An exception occurred
javax.faces.FacesException: Exception while calling encodeEnd on component : {Component-Path : [Class: javax.faces.component.UIViewRoot,ViewId: /jsp/secure/main.jsp][Class: org.apache.myfaces.custom.div.Div,Id: mainDiv3][Class: javax.faces.component.UINamingContainer,Id: subViewPlanning][Class: javax.faces.component.html.HtmlForm,Id: fPlanning][Class: javax.faces.component.html.HtmlPanelGrid,Id: planningPG5]}
	at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:559)
	at javax.faces.component.UIComponent.encodeAll(UIComponent.java:250)
	at javax.faces.component.UIComponent.encodeAll(UIComponent.java:246)
	at javax.faces.component.UIComponent.encodeAll(UIComponent.java:246)
	at javax.faces.component.UIComponent.encodeAll(UIComponent.java:246)
	at javax.faces.component.UIComponent.encodeAll(UIComponent.java:246)
	at org.apache.myfaces.application.jsp.JspViewHandlerImpl.actuallyRenderView(JspViewHandlerImpl.java:423)
	at org.apache.myfaces.application.jsp.JspViewHandlerImpl.renderView(JspViewHandlerImpl.java:380)
	at org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderResponseExecutor.java:41)
	at org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:140)
	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:152)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.myfaces.webapp.filter.ExtensionsFilter.doFilter(ExtensionsFilter.java:147)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
	at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
	at java.lang.Thread.run(Thread.java:619)
Caused by: javax.faces.FacesException: Exception while calling encodeEnd on component : {Component-Path : [Class: javax.faces.component.UIViewRoot,ViewId: /jsp/secure/main.jsp][Class: org.apache.myfaces.custom.div.Div,Id: mainDiv3][Class: javax.faces.component.UINamingContainer,Id: subViewPlanning][Class: javax.faces.component.html.HtmlForm,Id: fPlanning][Class: javax.faces.component.html.HtmlPanelGrid,Id: planningPG5][Class: javax.faces.component.html.HtmlSelectOneMenu,Id: planGeoDropdown1]}
	at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:559)
	at org.apache.myfaces.shared_impl.renderkit.RendererUtils.renderChild(RendererUtils.java:515)
	at org.apache.myfaces.shared_impl.renderkit.html.HtmlGridRendererBase.renderChildren(HtmlGridRendererBase.java:221)
	at org.apache.myfaces.shared_impl.renderkit.html.HtmlGridRendererBase.encodeEnd(HtmlGridRendererBase.java:102)
	at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:556)
	... 25 more
Caused by: javax.faces.convert.ConverterException: Test Converter Exception - getAsString(..)
	at at.pcd.wam.gegenstandsbereich.tmcWeb.common.PlanningPointConverter.getAsString(PlanningPointConverter.java:82)
	at org.apache.myfaces.taglib.core.DelegateConverter.getAsString(DelegateConverter.java:101)
	at org.apache.myfaces.shared_impl.renderkit.RendererUtils.getConvertedStringValue(RendererUtils.java:621)
	at org.apache.myfaces.shared_impl.renderkit.html.HtmlRendererUtils.getSubmittedOrSelectedValuesAsSet(HtmlRendererUtils.java:362)
	at org.apache.myfaces.shared_impl.renderkit.html.HtmlRendererUtils.internalRenderSelect(HtmlRendererUtils.java:337)
	at org.apache.myfaces.shared_impl.renderkit.html.HtmlRendererUtils.renderMenu(HtmlRendererUtils.java:288)
	at org.apache.myfaces.shared_impl.renderkit.html.HtmlMenuRendererBase.encodeEnd(HtmlMenuRendererBase.java:57)
	at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:556)
	... 29 more
```

JSP:

```
<h:message for="planGeoDropdown1" styleClass="errorMsg" />
<h:panelGrid id="planningPG5" columns="2" border="1">
			<h:outputText value="#{labels.planStartDropdown}"
				styleClass="outputText"
				rendered="#{planningContrl.renderGeoDropDownStart}" />
			<h:selectOneMenu id="planGeoDropdown1"
				value="#{planningContrl.geoStartDropDownSelected}"
				rendered="#{planningContrl.renderGeoDropDownStart}">
				<f:converter converterId="planningPointConverter" />
				<f:selectItems value="#{planningContrl.geoStartDropDownList}" />
			</h:selectOneMenu>
			<h:outputText value="#{labels.planEndDropdown}"
				styleClass="outputText"
				rendered="#{planningContrl.renderGeoDropDownEnd}" />
			<h:selectOneMenu id="planGeoDropdown2"
				value="#{planningContrl.geoEndtDropDownSelected}"
				rendered="#{planningContrl.renderGeoDropDownEnd}">
				<f:converter converterId="planningPointConverter" />
				<f:selectItems value="#{planningContrl.geoEndDropDownList}" />
			</h:selectOneMenu>
		</h:panelGrid>
```

Also wie mache ich es richtig?


----------



## maki (4. Mrz 2008)

Wann bitte sollte eine Converter Exception in der getAsString Methode aufgerufen werden ?
Eigentlich nie, schlieslich kann jeder notfalls die toString() Methode aufrufen, oder "" zurückgeben.

Es geht dabei haupsächlich um die getAsObject Methode, wirf doch mal dort


----------



## y0dA (4. Mrz 2008)

Alles klar!

Danke dir - bis zum nächsten mal 

**EDIT**


```
subViewPlanning:fPlanning:planGeoDropdown1: Ein Konvertierungsfehler ist aufgetreten.
```

Bekomme ich die Error Msg auch ohne:

```
subViewPlanning:fPlanning:planGeoDropdown1:
```


----------



## maki (4. Mrz 2008)

Das message tag hat ein paar attribute, probier doch mal ein paar aus.


----------



## y0dA (4. Mrz 2008)

maki hat gesagt.:
			
		

> Das message tag hat ein paar attribute, probier doch mal ein paar aus.



Wenn du showDetail und showSummary ansprichst, selbige bewirken keine Veränderung beim Fehlermeldungstext...


----------



## maki (8. Mrz 2008)

Welche JSF Implementierung & Version nutzt du?


----------



## stevy (27. Apr 2008)

Hallo,

mal eine Frage zu dem Sinn des Converters.

Wenn ich beim SelectItem das Objekt und eine Stringrepräsentation (das Label) angebe, wozu brauche ich dann noch einen Converter? Das Objekt ist doch schon im SelectItem gespeichert. Wenn sich die Selektion in der Combobox ändert, muss doch intern nur der "Zeiger" auf das aktuelle Objekt angepasst werden.

Ich würde dann erwarten, dass mir ein ValueChangeEvent über getNewValue() dieses aktuelle Objekt zurückgibt. Aber nein, stattdessen erhalte ich einen String, mit dem ich nicht viel anfangen kann. Bei komplexen Objekten mit Referenzen kann ich schlecht das Objekt aus einem String wiedererzeugen.

Verstehe es nicht. Hab ich irgendwo was übersehen?

Grüße, Stevy


----------

