# JPA und Entity-Klassen: Wert ungültig



## SuperMann (16. Jun 2012)

Hallo, ich hab folgendes Problem:

Ich hab zwei Entity Klassen die heißen: Person, Journey
Die Klasse Journey roll einen driver (also eine Person enthalten)

Wenn ich jedoch eine Journey in meine Datenbank speichern will bekomm ich immer die Meldung dass der Wert von driver ungültig ist. Ich weiß wirklich nicht wieso??? 

Hier sind mal meine Entities:

Person:

```
@Entity
public class Person implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @NotBlank
    @Column(nullable = false)
    private String firstname;
    @NotBlank
    @Column(nullable = false)
    private String lastname;
    @NotBlank
    @Column(nullable = false, unique = true)
    @Email
    private String email;
    @NotBlank
    @Size(min = 8)
    @Column(nullable = false)
    private String password;
    @OneToMany 
    private List<Journey> journeys = new ArrayList<Journey>();

//Getter & Setter...
```


Journey:

```
@Entity
public class Journey implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @Column(nullable = false)
    @NotBlank
    private String departure;
    @Column(nullable = false)
    @NotBlank
    private String destination;
    @Column(nullable = false)
    @NotNull
    @Temporal(javax.persistence.TemporalType.DATE)
    @Future
    private Date departureDate;
    @Column(nullable = false)
    @NotNull
    @Temporal(javax.persistence.TemporalType.TIMESTAMP)
    private Date departureTime;
    @Column(nullable = false)
    @NotBlank
    private String estimatedDuration;
    @Column(nullable = false)
    @NotBlank
    @Size(min=4)
    @Pattern(regexp="\\d{4,5}")
    private String departureZip;
    @Column(nullable = false)
    @NotBlank
    @Size(min=4)
    @Pattern(regexp="\\d{4,5}")
    private String destinationZip;
    @ManyToOne 
    private Person driver;
```



hier ist mein JSF File wo ich meine Journey eintrage:

```
<h:panelGrid columns="2" cellpadding="10">    
                            <h:outputLabel value="#{bundle.CreateJourneyLabel_driver}" for="driver" />
                            <h:selectOneMenu id="driver" value="#{journeyController.selected.driver}" title="#{bundle.CreateJourneyTitle_driver}" >
                                <f:selectItems value="#{personController.itemsAvailableSelectOne}"/>
                            </h:selectOneMenu>
                            <h:outputLabel value="#{bundle.CreateJourneyLabel_estimatedDuration}" for="estimatedDuration" />
                            <h:inputText id="estimatedDuration" value="#{journeyController.selected.estimatedDuration}"  required="true" />
                            <h:outputLabel value="#{bundle.CreateJourneyLabel_departureDate}" for="departureDate" />
                            <h:inputText id="departureDate" value="#{journeyController.selected.departureDate}"  required="true" >
                                <f:convertDateTime  type="date" pattern="dd.MM.yyyy"  />
                            </h:inputText>
                            <h:outputLabel value="#{bundle.CreateJourneyLabel_departure}" for="departure" />
                            <h:inputText id="departure" value="#{journeyController.selected.departure}" required="true" />
                            <h:outputLabel value="#{bundle.CreateJourneyLabel_departureTime}" for="departureTime" />
                            <h:inputText id="departureTime" value="#{journeyController.selected.departureTime}"  required="true" >
                                <f:convertDateTime type="time" pattern="HH:mm" />
                            </h:inputText>
                            <h:outputLabel value="#{bundle.CreateJourneyLabel_departureZip}" for="departureZip" />
                            <h:inputText id="departureZip" value="#{journeyController.selected.departureZip}"  required="true" />
                            <h:outputLabel value="#destination" for="destination" />
                            <h:inputText id="destination" value="#{journeyController.selected.destination}"required="true"/>
                            <h:outputLabel value="destination ZIP" for="destinationZip" />
                            <h:inputText id="destinationZip" value="#{journeyController.selected.destinationZip}"  required="true"/>
                        </h:panelGrid>  
                         <h:commandLink action="#{journeyController.create}" value="#{bundle.CreateJourneySaveLink}" />
```

Ich bekomm immer den Fehler:
j_idt41:j_idt49:driver: Überprüfungsfehler: Wert ist ungültig.

Ich weiß nicht was falsch ist??? 

Ich würd mich sehr über jeden Kommentar und jede Hilfe freuen

lg.


----------



## Fant (16. Jun 2012)

Interessant wären die Controller-Klassen... Versuchst du vielleicht einen String in _driver_ zu speichern? Hast du da einen passenden Konverter für geschrieben?


----------



## Nogothrim (16. Jun 2012)

Sieht mir auch so aus, ein Person Objekt in einem selectOneMenu ohne Converter auswählen sollte eigentlich nicht so wirklich funzen 
Thread gehört auch glaub ich eher ins EE Forum?


----------



## TimSkyp (16. Jun 2012)

Vielen Dank  

Ich bin noch neu in diesem Thema und hab auf den Converter vergessen, was ich jetzt aber nachgeholt habe.

Jetzt bekomm ich den Fehler mit dem "ungültigen Wert" jedoch nicht mehr aber leider wird der driver nicht mit zu meiner Journey gespeichert!

Könnte vielleicht noch etwas anders falsch sein? Oder ist die Verbindung nicht ausreichend definiert zwischen Journey und Person?

Hier ist mal der Code von meinem Converter, vielleicht liegst ja auch an dem??


```
@Named(value = "personConverter")
@FacesConverter(forClass = Person.class)
public class PersonConverter implements Converter {

    /**
     * Creates a new instance of PersonConverter
     */
    public PersonConverter() {
    }

    @Override
    public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
        if (value == null || value.length() == 0) {
            return null;
        }
        JourneyController controller = (JourneyController) facesContext.getApplication().getELResolver().
                getValue(facesContext.getELContext(), null, "journeyController");
        int hash = Integer.parseInt(value);
        Person person = controller.getSelected().getDriver();

        if (hash == (person.getEmail() + person.getFirstname() + person.getLastname() + person.getPassword()).hashCode()) {
            return person;
        }

        return null;
    }

    @Override
    public String getAsString(FacesContext fc, UIComponent uic, Object object) {
        if (object == null) {
            return null;
        }
        if (object instanceof Person) {
            Person person = (Person) object;
            return Integer.toString((person.getEmail() + person.getFirstname() + person.getLastname() + person.getPassword()).hashCode());
        } else {
            return null;
        }
    }
}
```


Hier ist der Ausschnitt wo ich den Converter in mein JSF File einbinde:


```
<h:selectOneMenu id="driver" value="#{journeyController.selected.driver}" converter="#{personConverter}">
               <f:selectItems value="#{personController.itemsAvailableSelectOne}" />
 </h:selectOneMenu>
```


Ich werde mal weiter recherchieren und hoff mal das ihr vielleicht einen Tipp habt für mich?

Passt die ManyToOne Beziehung vielleicht nicht bei driver in meinem Journey-Entity?


----------



## Fant (16. Jun 2012)

Fehlt dir in der @OneToMany-Annotation nicht noch ein "mappedBy"? Ob man das auch weglassen kann oder nicht weiß ich nicht, da kenn ich mich nicht gut genug aus..

Dein Konverter sieht für mich auf den ersten Blick aber etwas merkwürdig aus. Hast du dir vor dem Speichern mal ausgeben lassen, was für eine Person in _driver_ tatsächlich drin steht? Ich vermute, dass dein Konverter immer null zurückgibt, denn um eine Person in _driver_  abzulegen brauchst du doch die getAsObject-Methode vom Konverter. In dieser greifst du nun aber schon auf dieses Feld zu.

Einen HashCode würde ich da nicht verwenden, denn der liefert dir keine eindeutige Zuweisung von einem HashCode zum passenden Objekt. Außerdem wird der Benutzer sich doch unter dem HashCode nix vorstellen können, wenn er diesen sieht. Nimm doch z.B. die ID + Vor- und Nachname. In der getAsObject-Methode extrahierst du die ID aus dem String und suchst über den EntityManager die passende Person. Es gibt natürlich noch zig andere Varianten .. per Google-Suche findest du da schnell zahlreiche Anregungen.


----------



## TimSkyp (17. Jun 2012)

Ich komm mir zwar schon richtig blöd bei meinen Fragen vor, aber ich kenn mich im Moment überhaupt nicht mehr aus  

Ich hab bei meinem PersonController eine innere Klasse die heißt PersonControllerConverter.
Kann ich die vielleicht verwenden um meinen driver in eine Person zu convertieren oder muss ich wirklich eine eigenen Converter schreiben?

Hier is mal die innere Klasse PersonControllerConverter:


```
@FacesConverter(forClass = Person.class)
    public static class PersonControllerConverter implements Converter {

        @Override
        public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
            if (value == null || value.length() == 0) {
                return null;
            }
            PersonController controller = (PersonController) facesContext.getApplication().getELResolver().
                    getValue(facesContext.getELContext(), null, "personController");
            return controller.ejbFacade.find(getKey(value));
        }

        java.lang.Long getKey(String value) {
            java.lang.Long key;
            key = Long.valueOf(value);
            return key;
        }

        String getStringKey(java.lang.Long value) {
            StringBuilder sb = new StringBuilder();
            sb.append(value);
            return sb.toString();
        }

        @Override
        public String getAsString(FacesContext facesContext, UIComponent component, Object object) {
            if (object == null) {
                return null;
            }
            if (object instanceof Person) {
                Person o = (Person) object;
                return getStringKey(o.getId());
            } else {
                throw new IllegalArgumentException("object " + object + " is of type " + object.getClass().getName() + "; expected type: " + PersonController.class.getName());
            }
        }
    }
```


wenn ja wie?


----------



## TimSkyp (17. Jun 2012)

Also, ich hab jetzt endlich eine funktionierende Lösung gefunden 

Ich möcht mich noch mal bei allen Helfern bedanken, und möchte hier meine Lösung dokumentieren, falls sonst noch wer einmal das selbe Problem hat wie ich! 

Ich hab in meine Person Entity-Klasse eine Methode hinzugefügt:


```
public Converter getConverter() {
        return new Converter() {

            @PersistenceContext
            EntityManager entityManager;

            @Override
            public Object getAsObject( FacesContext fc, UIComponent uic, String string) {
                return (string == null) ? null : entityManager.find(Person.class, Long.parseLong(string));
            }

            @Override
            public String getAsString(FacesContext fc, UIComponent uic, Object o) {
                return (o == null) ? null : Long.toString(((Person) o).getId());
            }
        };
    }
```

und eine equals-Methode: 


```
@Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Person other = (Person) obj;
        if (this.id != other.id && (this.id == null || !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }
```


aufgerufen wird diese folgend in meinem JSF file:


```
<h:selectOneMenu id="driver" value="#{journeyController.selected.driver}" 
              converter="#{Person.converter}" >
             <f:selectItems value="#{personController.itemsAvailableSelectOne}"/>
  </h:selectOneMenu>
```


Wünsch allen Lesen noch einen wunder schönen Tag!!


----------

