I have a jsf form in which the user type an int and a string value, which are stored in database after clicking on a Save button.
<h:form id="TbtestCreateForm">
<p:inputText value="#{tbtestController.selected.name}" />
<p:commandButton actionListener="#{tbtestController.saveNew}" value="#{myBundle.Save}" />
</h:form>
I'm using EJBs with façade pattern, which does the CRUD actions defined in AbstractController class, which uses the AbstractFacade that 'binds' the entity class.
What I need is to hard code/set manually the string value in the form and store it in database along with the int value informed by the user, in the same operation (the same object).
I've tried to do as below, but no success:
@Named
public class MyBean implements Serializable {
@Inject
TbtestController tbtestController;
private String myName;
//GETTERS AND SETTERS
@PostConstruct
public void init() {
myName = "some foo name";
Tbtest myTbtest = new Tbtest();
myTbtest.setName(myName);
tbtestController.setSelected(myTbtest);
tbtestController.saveNew(null); // to simulate what the savNew method do
}
I've created a small netbeans project available to be cloned at: https://github.com/f6750699/webAppTest.git
Below, follows 2 methods defined in the AbstractController class:
The saveNew method:
public void saveNew(ActionEvent event) {
String msg = ResourceBundle.getBundle("/MyBundle").getString(itemClass.getSimpleName() + "Created");
persist(PersistAction.CREATE, msg);
if (!isValidationFailed()) {
items = null; // Invalidate list of items to trigger re-query.
}
}
The persist method:
private void persist(PersistAction persistAction, String successMessage) {
if (selected != null) {
this.setEmbeddableKeys();
try {
if (persistAction != PersistAction.DELETE) {
this.ejbFacade.edit(selected);
} else {
this.ejbFacade.remove(selected);
}
JsfUtil.addSuccessMessage(successMessage);
} catch (EJBException ex) {
Throwable cause = JsfUtil.getRootCause(ex.getCause());
if (cause != null) {
if (cause instanceof ConstraintViolationException) {
ConstraintViolationException excp = (ConstraintViolationException) cause;
for (ConstraintViolation s : excp.getConstraintViolations()) {
JsfUtil.addErrorMessage(s.getMessage());
}
} else {
String msg = cause.getLocalizedMessage();
if (msg.length() > 0) {
JsfUtil.addErrorMessage(msg);
} else {
JsfUtil.addErrorMessage(ex, ResourceBundle.getBundle("/Bundle").getString("PersistenceErrorOccured"));
}
}
}
} catch (Exception ex) {
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, null, ex);
JsfUtil.addErrorMessage(ex, ResourceBundle.getBundle("/MyBundle").getString("PersistenceErrorOccured"));
}
}
}
I really appreciate some help with it, because I got stuck on it for a while already.
Thanks in advance.
Paul Morris solution
I've concentrated in one class, as Paul suggested:
@Named
@ViewScoped
public class TbtestController extends AbstractController<Tbtest> {
@EJB
private TbtestFacade ejbFacade;
public TbtestController() {
super(Tbtest.class); //-> there is already an invocation here, see below
}
@PostConstruct
@Override
public void init() {
super.setFacade(ejbFacade);
//Paul Morris solution below
myName = "some foo name";
this.setMyName(myName);
this.saveNew(null); // to simulate what the savNew method do
}
private String myName;
public void setMyName(String name) {
myName = name;
}
@Override
public void saveNew(ActionEvent event) {
this.getSelected().setName(myName);
//super.(event); // -> invocation of a superclass constructor must be the first line in the subclass constructor, but there is already one invocation, see above. Then, I've tried to invoke the super method:
super.saveNew(event); // but this didn't resolved, as it launches a NullPointerException, see below.
}
}
The Exception:
org.jboss.weld.exceptions.WeldException: WELD-000049: Unable to invoke public void beans.TbtestController.init() on beans.TbtestController@37668b21
[...]
Caused by: java.lang.NullPointerException
at beans.TbtestController.saveNew(TbtestController.java:40)
at beans.TbtestController.init(TbtestController.java:29)
... 87 more
You're going about this all wrong. Leave the AbstractController class as generated. Instead, modify the derived class, TbtestController and add a property for the hard coded string. Then override the saveNew method, like so:
private String myName;
public void setMyName(String name) {
myName = name;
}
@Override
public void saveNew(ActionEvent event) {
this.getSelected().setName(myName);
super.saveNew(event);
}
Your bean method should then be coded something like this:
@PostConstruct
public void init() {
myName = "some foo name";
tbtestController.setMyName(myName);
}
though I'm not certain why you have the MyBean class at all. Hard code the string in the Controller and then just use the Controller saveNew method in the form like you have at the top of your question.
UPDATE
Try this ...
@Named
@ViewScoped
public class TbtestController extends AbstractController<Tbtest> {
@EJB
private TbtestFacade ejbFacade;
public TbtestController() {
super(Tbtest.class); //-> there is already an invocation here, see below
}
@PostConstruct
@Override
public void init() {
super.setFacade(ejbFacade);
//Paul Morris solution below
myName = "";
}
private String myName;
public void setMyName(String name) {
myName = name;
}
public String getMyName(String name) {
if (myName.isEmpty()) {
myName = "Default Value";
}
return myName;
}
@Override
public void saveNew(ActionEvent event) {
this.getSelected().setName(this.getMyName(myName));
super.saveNew(event);
}
}