# EJB liefert keine ID



## Kris (21. Mrz 2011)

Hallo zusammen

Ich habe eine Entityklasse, dazu eine DAO Klasse, die die Daten von einem JBoss Server erhält. Ich habe die DAO Klasse als Bean Project auf dem Server deployed und versuche die Daten auszulesen. Alles klappt soweit, bis auf die Kleinigkeit, das die ID nicht vom Server zum Client gelangt. 
Das heisst, wenn ich die Serverseite debugge, wird in das Objekt die Id eingetragen, wenn dieses über den Naming Context an den Client geliefert wird, kommt es ohne ID an. 

Woran kann das liegen?


----------



## JimPanse (21. Mrz 2011)

Verwendest du ein Remote Interfaces? Wenn ja, dann ist ein kein Call-by-reference Aufruf! Das ist nur der Fall wenn du ein Local-Interface verwendest!

s.h. Local and Remote EJB Interfaces - O'Reilly Media

"...when using local interfaces, ...., but this time you get a reference to a real Java object on the heap, instead of a stub to a remote object."


----------



## Kris (22. Mrz 2011)

Das schon, aber warum liefert denn ein call by value aufruf die ID nicht?
Alle anderen Daten werden ja auch kopiert.


----------



## JimPanse (22. Mrz 2011)

Das ist doch kein "Call-by-value" Aufruf!

Ich kenne deinen Anwendungsfall nicht aber ich glaube du erstellst im Client ein neues Objekt und willst dieses dann über eine SessionBean speichern. EJB handelt das ganze folgender maßen ab:

1. Local Interfaces -> Ist ein Aufruf der in der gleichen JVM läuft d.h. Call by Reference!
Wenn du em.persist(entity) oder em.merge(entity) Aufrufst hat das Objekt im Anschluss eine Id und deine Methode benötigt keinen Rückgabewert weil du mit einer Reference des Objekts arbeitest.

2. Remote Interfaces-> Ist ein Aufruf der nicht in der gleichen JVM erfolgt -> RMI (Remote Method Invocation) d.h. du arbeitest mit einem Stub! Dann muss deine Methode einen Rückgabewert haben in dem Fall das gespeicherte oder veränderte Objekt!

Wenn der Client und das EJB-Projekt in dem gleichem EAR liegen brauchst du keine Remote-Interfaces....


----------



## Kris (22. Mrz 2011)

Client und EJB liegen nicht im selben EAR.

Folgendes Szenario ist gegeben. JBoss 6 und die Bean ist als jar im deploy Ordner. Oder zur Zeit eher aus Eclipse heraus gestartet.

Danach wird ein JUnit Test ausgeführt. Dieser schreibt und liest Daten aus einer Stateless EJB, die auf die Datenbank zugreifft und beim auslesen Objekte liefert.

Wenn ich Debugge, enthalten die ausgelesenen Objekte, in der Bean die Id. Der JUnit Test kriegt diese jedoch nicht geliefert. Zwar alle Objekte und die Daten darin, nur keine Datenbank ID.


```
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;

/**
 * @author Christof Kulesza
 * 
 */
@MappedSuperclass
public class AbstractEntity {

	private long id;

	protected AbstractEntity() {

	}

	/**
	 * Gibt die ID, die von der Persistenzschicht vergeben wird, zurück.
	 * 
	 * @return the id
	 */
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	public long getId() {
		return id;
	}

	/**
	 * Setzt die ID, die von der Persistenzschicht vergeben wird.
	 * 
	 * @param id
	 *            the id to set
	 */
	public void setId(long id) {
		this.id = id;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + (int) (id ^ (id >>> 32));
		return result;
	}

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

	@Override
	public String toString() {
		return "AbstractEntity [id=" + id + "]";
	}
}
```


```
import java.io.Serializable;
import java.util.Calendar;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
public class Blink extends AbstractEntity implements Serializable {

	private static final long serialVersionUID = -7471434756339687176L;
	private Calendar reciveDate;
	protected Blink() {

	}

	public Blink(Calendar reciveDate) {
		this.reciveDate = reciveDate;
	}

	@Temporal(TemporalType.TIMESTAMP)
	public Calendar getReciveDate() {
		return reciveDate;
	}

	public void setReciveDate(Calendar reciveDate) {
		this.reciveDate = reciveDate;
	}
...
}
```


```
import java.util.List;

import javax.ejb.Remote;

import com.sitf.trenino.models.AbstractEntity;
import com.sitf.trenino.server.datacenter.exceptions.DataAccessException;

@Remote
public interface EntityDAOBeanRemote {

	public long insertEntity(AbstractEntity entity) throws DataAccessException;

	public boolean deleteEntity(AbstractEntity entity)
			throws DataAccessException;

	public AbstractEntity findEntity(AbstractEntity entity)
			throws DataAccessException;
}
```


```
import java.io.Serializable;
import java.util.List;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import com.sitf.trenino.models.AbstractEntity;
import com.sitf.trenino.server.datacenter.exceptions.DataAccessException;

@Stateless
public class EntityDAOBean implements EntityDAOBeanRemote, EntityDAOBeanLocal,
		Serializable {

	private static final long serialVersionUID = -7964793716886757785L;

	@PersistenceContext(unitName = "masterclassEjbPersistence")
	private EntityManager em;

	/**
	 * Default constructor.
	 */
	public EntityDAOBean() {
	}

	@Override
	public long insertEntity(AbstractEntity entity) throws DataAccessException {
		try {
			em.persist(entity);
		} catch (Exception e) {
			throw new DataAccessException("Entity ("
					+ entity.getClass().getSimpleName()
					+ ") couldn't be insert.", e);
		}
		return entity.getId();
	}

	@Override
	public boolean deleteEntity(AbstractEntity entity)
			throws DataAccessException {
		try {
			em.remove(entity);
		} catch (Exception e) {
			throw new DataAccessException("Entity ("
					+ entity.getClass().getSimpleName()
					+ ") couldn't be deleted.", e);
		}
		return true;
	}

	@Override
	public AbstractEntity findEntity(AbstractEntity entity)
			throws DataAccessException {
		try {
			return em.find(AbstractEntity.class, entity.getId());
		} catch (Exception e) {
			throw new DataAccessException("Entity ("
					+ entity.getClass().getSimpleName()
					+ ") couldn't be found.", e);
		}
	}
}
```


----------



## JimPanse (22. Mrz 2011)

Klar der JUNIT-Test wird in deiner IDE ausgeführt d.h. andere JVM dann brauchst du das Remote-Interface! bitte poste mal deine UNIT-Test Klasse dann kann ich dir sagen wo der Fehler liegt!


----------



## Kris (22. Mrz 2011)

```
import static org.junit.Assert.assertEquals;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import com.sitf.trenino.antennas.IngecomActiveAntenna;
import com.sitf.trenino.models.AbstractEntity;
import com.sitf.trenino.models.Antenna;
import com.sitf.trenino.models.Train;
import com.sitf.trenino.server.datacenter.exceptions.DataAccessException;

public class InitializeTest {

	private static Hashtable<String, String> env;
	private static EntityDAOBeanRemote tagBean;

	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		env = new Hashtable<String, String>();
		env.put(Context.INITIAL_CONTEXT_FACTORY,
				"org.jnp.interfaces.NamingContextFactory");
		env.put(Context.PROVIDER_URL, "localhost:1099");
		env.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
	}

	@AfterClass
	public static void tearDownAfterClass() throws Exception {
	}

	@Test
	public void createTagDAOBean() {
		Object result = null;
		InitialContext ctx;
		try {
			ctx = new InitialContext(env);
			result = ctx.lookup("EntityDAOBean/remote");
			ctx.close();
		} catch (NamingException e) {
			e.printStackTrace();
		}
		tagBean = (EntityDAOBeanRemote) result;
	}

	@Test
	public void deleteAllBlinks() {
		try {
			List<Blink> blinks = tagBean.getAllBlinks();
			for (int i = 0; i < blinks.size(); i++) {
				tagBean.deleteEntity(blinks.get(i));
			}
		} catch (DataAccessException e) {
			e.printStackTrace();
		}
	}

}
```

Die getAllBlinks Methode sieht so aus.


```
@Override
	public List<Tunnel> getAllBlinks() throws DataAccessException {
		Query query = em.createQuery("Select b From Blink b");
		@SuppressWarnings("unchecked")
		List<Blink> blinks = query.getResultList();
		return blinks;
	}
```


----------



## JimPanse (22. Mrz 2011)

ein paar Anmerkung 

1. Der Konstruktor von Blink ist protected statt public
2. Verwende statt "long" die Wrapper Klasse "Long" die ist Serializable
3. Prüfe deine Methode getAllBlinks!!!!!

```
public List<Tunnel> getAllBlinks() throws DataAccessException
```
gibt aber eine List<Blink> blinks zurück!!!!!!!



3. Sauberkeit 

```
@BeforeClass
	public static void setUpInitialContext() throws Exception {
		context = new InitialContext();

// Initialisierungen
	}
	@AfterClass
	public static void tearDownInitialContext() throws Exception {
		context.close();
	}

@Test
public void testBean(){....}
```


----------



## Kris (22. Mrz 2011)

Das Schliessen des Context in der createTagDAOBean ist nicht sauber?

Aber es lag daran, dass AbstractEntity kein Serialize implementiert. Echt dämlich.

Vielen Dank. Hast was gut bei mir.


----------



## JimPanse (22. Mrz 2011)

upps das habe ich auch übersehen... naja über ein Test-case die Bean initialisieren ist nicht gerade sauber dafür gibt es ja die globalen Methoden:
@BeforeClass oder auch 
@Before (falls man nicht mit static arbeiten möchte)

Insbesondere bist du damit an eine bestimmte Reihenfolge gebunden!!! Der Test createTagDAOBean muss immer vor allen anderen ausgeführt werden sonst ist EntityDAOBeanRemote null!


----------

