# Converter + Zugriff auf DAO und EntityManager



## kiwie (25. Sep 2013)

Hi,
ich habe folgendes Problem:
ich möchte ein SelectOneMenu verwenden, um ne auswahl zu geben und das dann zu speichern.
da habe ich gelesen, dass man nen converter braucht, um die Objekte da richtig rauszubekommen. Nun hab ich einen Converter geschrieben. Allerdings dann auch erfahren, dass es erst am JSF 2.2 möglich ist Beans in diesen zu injecten. (Ich verwende nur die jsf-api von com.sun.faces version 2.0.2 und das upgraden scheint ziemlich kompliziert.. da geht dann gar nichts mehr).
also habe ich versucht das anders zu machen. wenn ich die verwendete DAO im converter selbst mit new ... instanziiere, dann klappt das soweit. Nur in der DAO selbst bekommt er dann keinen EntityManager, der eigentlich automatisch injected sein müsste. (und bei andren methodenaufrufen über einen Service klappt das auch. die DAO ist also in Ordnung).

Der Converter (ein paar von meinen Lösungsversuchen sind da auskommentiert):

```
//@Component
//@Scope("request")
@FacesConverter("com.barbeit.web.converter.StudentConverter")
public class StudentConverter implements Converter{

//	@Autowired //hat nicht funktioniert
	private static StudentDAOImpl studentDAO = new StudentDAOImpl();

	
    @Override
//    @Transactional (readOnly = false)
    public Object getAsObject(FacesContext context, UIComponent component, String newValue) {
    	// Convert the unique String representation of Student to the actual Student object.
    	//Ausgaben zum Ueberpruefen:
    	System.out.println("new value(als String): "+ newValue);
    	String s;
    	if (studentDAO == null){
    		s="keine studentDAO";
    	} else { s="okay";}
    	System.out.println("studentDAO: " + s);
    	
    	int i = Integer.parseInt(newValue);
    	System.out.println("als Integer: "+i);

    	return studentDAO.getById(Integer.parseInt(newValue));
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
    	// Convert the Student object to its unique String representation.
        return String.valueOf(((Student) value).getId());
    }

	public static StudentDAO getStudentDAO() {
		return studentDAO;
	}

	public static void setStudentDAO(StudentDAOImpl studentDAO) {
		StudentConverter.studentDAO = studentDAO;
	}  
}
```

ein Teil aus der Entity:

```
// This must return true for another Student object with same id.
	@Override
    public boolean equals(Object other) {
    	if (other == null) {
            return false;
        } else if (!(other instanceof Student)) {
            return false;
        } else if (Integer.toString(((Student) other).getId()).equals(Integer.toString(this.id))) {
            return true;
        } else {
            return false;
        }
    }

    // This must return the same hashcode for every Student object with the same id.
	@Override
    public int hashCode() {
        return id != 0 ? this.getClass().hashCode() + id : super.hashCode();
    }
```

ein Teil aus der xhtml:

```
<h:outputLabel for="StudentMenu" value="Student (bis Student ueberg. funkt.): *" /> 
        	<p:selectOneMenu id="StudentMenu" value="#{effortService.stud}" effect="fade">  
           		<f:selectItem itemLabel="Select One" itemValue="" />
            	<f:selectItems value="#{effortService.students}" var="Student" 
            	itemLabel="#{Student.rzPerson.name}, #{Student.rzPerson.firstName}"/>
        	</p:selectOneMenu>
```

aus der DAO:

```
@Repository("studentDAO")
@Scope(value="request")
public class StudentDAOImpl implements StudentDAO{

	@PersistenceContext
	private EntityManager em;

//getter und setter und andere CRUD methoden

public Student getById(int id) {
		//Ausgaben zum ueberpruefen:
		System.out.println("id: "+ id);
		String s;
    	if (em == null){
    		s="kein EntityManager!";
    	} else { s="okay";}
    	System.out.println("EntityManager: " + s);
    	
		return getEntityManager().find(Student.class, id);
	}
```

wenn ihr sonst noch infos braucht...
danke schon ma für die mühe...

ach ja ich frag mich auch, ob ich eigentlich wirklich einen Converter brauche? bevor ich einen hatte, konnte ich die Entities immerhin ja anzeigen, nur habe ich da immer nur null herausbekommen beim speichern. Lag das daran, dass der Converter gefehlt hat oder mach ich die ganze mühe umsonst?

Bzw. findet ihr es klüger die JSF version irgendwie zu ändern? (und wenn ja wie stell ich das am geschicktesten an und was muss ich so ändern?)


----------



## tandraschko (25. Sep 2013)

Die Injection in Converter haben sie gestrichen und würde eh nur mit CDI gehen - nicht mit Spring.
Somit musst du für Spring eine Lösung finden - Spicken könntest du bei CODI und den Code für Spring adaptieren.
Falls es sowas nicht im Internet gibt, würde ich es nicht raten, wenn man sich mit den Frameworks intern noch nicht befasst hat.

Ich würde einfach per Hand deine SpringBeans in den Converter holen oder einen abstrakten Converter entwickeln der dir die Injection im Constructor macht (falls sowas mit Spring geht).


Raten würde ich dir trotzdem auf jedenfall JSF bis zur letzten 2.1 Version upzugraden oder gleich auf MyFaces zu gehen - rein von den Performance und den Bugs.


----------



## sence (25. Sep 2013)

Wenn du den Converter nur an einer Stelle verwendest, kann du auch ohne DAO arbeiten und ein wenig Performance gewinnen, in dem auf die Liste mittels ELResolver direkt zu greifst:


```
public Object getAsObject(FacesContext context, UIComponent component, String newValue) {

FacesContext context = FacesContext.getCurrentInstance();
EffortService ES = (EffortService) context.getELContext().getELResolver().getValue(context.getELContext(), null,"effortService");

if(ES != null)
    for(Studen S : ES.students)
         if(S.id == Integer.parseInt(newValue))
             return S;

return null; // nicht gefunden
}
```


----------



## kiwie (26. Sep 2013)

Danke @sence: das hat soweit geklappt, aber ich befürchte, dass ich den converter auch wo anders noch brauchen werde... hast du da auch so ne idee?
@tandraschko: per hand hab ich's ja versucht mit der DAO, aber der entitymanager in der DAO wird dann nicht injected... weißt du warum das so ist? wird der auch nur injected wenn die DAO selbst durch Injection gebaut wurde?
puh mit abstraktem converter hab ich mich noch gar nicht befasst. hast du da zufällig n gutes tut ?


----------



## sence (26. Sep 2013)

ich gebe Dir nur den Denkansatz, wenn du es nicht selbst heraus findest gib bescheid 

Schau nach woher der "Call" kommt, bzw in welcher Umgebung der Converter angefordert wurde, dementsprechend 
holst du die benötigte Bean und die Liste

*Abstrakt*
if(condition == 1)
-> Bean x holen
-> Liste aus Bean x holen
else if(condition == 2)
-> Bean y holen
-> Liste aus Bean y holen

du hast hierbei zwar eine "harte" Verdrahtung, je nach Anzahl der zu ladenden Elemente (und zusätzlicher RAM usw...) macht es einen rießen Unterschied aus im Gegensatz zu der DB basierenden Abfrage.

VG


----------



## kiwie (26. Sep 2013)

nach deinem tipp hab ichs so versucht:


```
context = FacesContext.getCurrentInstance();
        
        if (component.getId() == "StudentMenu"){
        	EffortService ES = (EffortService) context.getELContext().getELResolver().getValue(context.getELContext(), null,"effortService");
	        if(ES != null){
	            for(Student S : ES.getStudents()){
	                 if(S.getId() == Integer.parseInt(newValue)){
	                     return S;
	                 }
	            }
	        }
	        return null; // nicht gefunden
        } else {
       
        return null; // keine komponente gefunden
        }
```

leider funktioniert die bedingung im if so nicht und er springt gleich nach unten auf return null;
obwohl ich mir auch das getId(); mal habe ausgeben lassen und da StudentMenu heraus kam....


----------



## sence (26. Sep 2013)

```
if (component.getId() == "StudentMenu"){
```

wie werden in Java zwei Strings miteinander verglichen :- )
component.getId().equals("StudentMenu");


----------



## kiwie (27. Sep 2013)

Ups.... :-D Jetzt klappts ;-) Danke!


----------

