I am relatively new to Java EE and I am a bit confused as to how I access a stateless Java Bean from my Enterprise Application Client.
My intention is for my enterprise bean, CarReposityImpl, to handle database access and entity management for an entity class called Car.
My CarRepositoryImpl looks like:
@Stateless
public class CarRepositoryImpl implements CarRepository
{
@PersistenceContext(unitName = "FIT5042AssignmentEJBPU")
private EntityManager entityManager;
@Override
public void addCar(Car car)
{
entityManager.persist(car);
}
@Override
public Car searchByVIN(String vin) throws Exception
{
Car car = entityManager.find(Car.class, vin);
return car;
}
@Override
public List<Car> getAllCars() throws Exception
{
return entityManager.createNamedQuery(Car.GET_ALL_QUERY_NAME).getResultList();
}
@Override
public void removeCar(String vin) throws Exception
{
Car car = searchByVIN(vin);
if (car != null)
{
entityManager.remove(car);
}
}
@Override
public void editCar(Car car) throws Exception
{
entityManager.merge(car);
}
}
It implements the interface CarRepository that looks like:
@Remote
public interface CarRepository
{
public void addCar(Car car);
public Car searchByVIN(String vin) throws Exception;
public List<Car> getAllCars() throws Exception;
public void removeCar(String vin) throws Exception;
public void editCar(Car car) throws Exception;
}
The entity class Car looks like:
@Entity
@Table(name = "CAR")
@NamedQueries({@NamedQuery(name = Car.GET_ALL_QUERY_NAME, query = "SELECT c FROM Car AS c")})
public class Car implements Serializable
{
public static final String GET_ALL_QUERY_NAME = "Car.getAll";
//private Sale sale;
String modelNo, VIN, model, make, type, thumbnail, description, prevURL;
public Car() {
}
public Car(String varModelNo, String varVIN, String varModel, String varMake, String varType, String varThumb, String varDesc, String varPrevURL)
{
modelNo = varModelNo;
VIN = varVIN;
model = varModel;
make = varMake;
type = varType;
thumbnail = varThumb;
description = varDesc;
prevURL = varPrevURL;
}
public void setModelNo(String varModNo){modelNo = varModNo;}
public void setVIN(String varVIN){VIN = varVIN;}
public void setModel(String varMod){model = varMod;}
public void setMake(String varMake){make = varMake;}
public void setType(String varType){type = varType;}
public void setThumbnail(String varThumb){thumbnail = varThumb;}
public void setDesc(String varDesc){description = varDesc;}
public void setPrevURL(String varPrev){prevURL = varPrev;}
@Column(name = "modelNo")
public String getModelNo(){return modelNo;}
@Id
@Column(name = "VIN")
public String getVIN(){return VIN;}
@Column(name = "model")
public String getModel(){return model;}
@Column(name = "make")
public String getMake(){return make;}
@Column(name = "type")
public String getType(){return type;}
@Column(name = "thumbnail")
public String getThumbnail(){return thumbnail;}
@Column(name = "description")
public String getDesc(){return description;}
@Column(name = "prevURL")
public String getPrevURL(){return prevURL;}
}
From my understanding I should be able to add this line:
public class CarSales
{
@EJB
private static CarRepository carRepo;
to the class in my Enterprise Application Client that handles my business logic and then I should be able to it to call the methods inside my CarRepositoyImpl bean to access the my database. I am pretty sure I am not supposed to instantiate the carRepo object like a normal object because the EJB container is supposed to handle that.
Essentially I want to be able to use my stateless bean in my Application client like this:
List<Car> cars = carRepo.getAllCars();
but when I do it throws a null pointer exception and I have no idea why.
My application client class as it currently stands, it is mostly incomplete:
public class CarSales
{
@EJB
private static CarRepository carRepo;
private final MainScreen main;
public CarSales()
{
main = new MainScreen();
addCarActionListeners();
}
public void run()
{
displayAllCars();
}
private void displayAllCars()
{
main.getCarScreen().clearTable();
try
{
List<Car> cars = carRepo.getAllCars();
for(Car car : cars)
{//"VIN", "Model Number", "Model Name", "Make", "Thumbnail", "Description", "URL"
String[] data = new String[7];
data[0] = car.getVIN();
data[1] = car.getModelNo();
data[2] = car.getModel();
data[3] = car.getMake();
data[4] = car.getThumbnail();
data[5] = car.getDesc();
data[6] = car.getPrevURL();
main.getCarScreen().getModel().addRow(data);
}
}
catch(Exception ex)
{
main.getCarScreen().outputAddError(ex.getMessage());
System.out.println("failed");
ex.printStackTrace();
}
}
private void addCarActionListeners()
{//CLOSE
main.getCarScreen().getClose().addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
main.closeWindow();
}
});
main.getCarScreen().getAdd().addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
Car car = new Car(main.getCarScreen().getModelNo(),
main.getCarScreen().getVin(),
main.getCarScreen().getModelName(),
main.getCarScreen().gerMake(),
main.getCarScreen().getType(),
main.getCarScreen().getThumb(),
main.getCarScreen().getDesc(),
main.getCarScreen().getUrl());
try
{
System.out.println("try");
carRepo.addCar(car);
displayAllCars();
}
catch(Exception ex)
{
System.out.println("catch");
//main.getCarScreen().outputAddError(ex.getMessage());
System.out.println(ex.getMessage());
}
}
});
}
}
Stack trace of my error:
java.lang.NullPointerException
at CarSales.CarSales.displayAllCars(CarSales.java:45)
at CarSales.CarSales.run(CarSales.java:36)
at CarSales.Main.main(Main.java:18)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.glassfish.appclient.client.acc.AppClientContainer.launch(AppClientContainer.java:446)
at org.glassfish.appclient.client.AppClientFacade.main(AppClientFacade.java:166)
Line 45 is:
List<Car> cars = carRepo.getAllCars();
Made some suggested changes to my CarSales Class:
public class CarSales
{
@EJB
private CarRepository carRepo;
private final MainScreen main;
public CarSales()
{
main = new MainScreen();
}
@PostConstruct
public void init()
{
addCarActionListeners();
}
public void run()
{
displayAllCars();
}
My main function that calls run:
public class Main
{
public static void main(String[] args)
{
CarSales sys = new CarSales();
sys.run();
}
}
If you create an object yourself, then the container has no chance to perform injection. In the client container, effectively only the main class is eligible for injection. Try:
public class Main
{
@EJB
private static CarRepository carRepo;
public static void main(String[] args)
{
CarSales sys = new CarSales(carRepo);
sys.run();
}
}
public class CarSales
{
private final CarRepository carRepo;
private final MainScreen main;
public CarSales(CarRepository carRepo)
{
this.carRepo = carRepo;
main = new MainScreen();
}
Alternatively, you can declare the reference in your main class, and then look up the EJB reference from anywhere in the client application:
@EJB(name="ejb/carRepo", beanInterface=CarRepository.clas)
public class Main
{
public static void main(String[] args)
...
CarRepository carRepo = (CarRepository)new InitialContext().lookup("java:comp/env/ejb/carRepo");