I am learning JSF/EJB and I have run into a problem.
I am trying to write a code that takes a string from user and store that string to database.
Here's my code:
Entity bean:
#Entity
public class TestTable implements Serializable {
private static final long serialVersionUID = 1L;
public TestTable() {
super();
}
#Id
#GeneratedValue
private int firstcolumn;
private String secondcolumn;
private String testphrase = "test phrase";
public String getTestphrase() {
return testphrase;
}
public void setTestphrase(String testphrase) {
this.testphrase = testphrase;
}
public int getFirstcolumn() {
return firstcolumn;
}
public void setFirstcolumn(int firstcolumn) {
this.firstcolumn = firstcolumn;
}
public String getSecondcolumn() {
return secondcolumn;
}
public void setSecondcolumn(String secondcolumn) {
this.secondcolumn = secondcolumn;
}
}
Table has three columns, first column is primary key, second column stores string entered by user and third column stores "test phrase".
Controller bean:
#Named
public class TestController implements Serializable {
private static final long serialVersionUID = 1L;
#EJB
DataAccess dacc;
#Inject
TestTable testTable;
public TestController()
{
}
public TestTable getTestTable() {
return testTable;
}
public void setTestTable(TestTable testTable) {
this.testTable = testTable;
}
public void test()
{
System.out.println("string secondcolumn= "+ testTable.getSecondcolumn());
dacc.addtodb(testTable);
}
}
I used System.out.println("string secondcolumn= "+ testTable.getSecondcolumn()); in method test() to check data before it is written to database. My problem is, it is always null. Output in console :
INFO :string secondcolumn= null .
secondcolumn is not set by value binding expression in JSF.
Now, JSF:
<h:outputText value="Second column:">
</h:outputText>
<h:inputText label="Second column" value="#{testController.testTable.secondcolumn}">
</h:inputText>
<h:outputText value="#{testController.testTable.getTestphrase()}">
</h:outputText>
<h:commandButton action="#{testController.test}" value="Save">
</h:commandButton>
I checked database and rows are being added. Entries in Column SECONDCOLUMN are NULL.
Entries in TESTPHRASE are "test phrase". I get no error messages and I have tried everything I can to solve the problem and now I am stuck. Any feedback are welcome.
Your problem is that you're injecting an entity class. The best will be initializing it manually using the new keyword, retrieving the entity from database, etc. One way to do this would be using a #PostConstruct method in your CDI bean:
#Named
//here you should define the scope of your bean
//probably #RequestScoped
//if you're working with JSF 2.2 there's already a #ViewScoped
public class TestController implements Serializable {
private static final long serialVersionUID = 1L;
#EJB
DataAccess dacc;
//this musn't be injected since it's not a business class but an entity class
//#Inject
TestTable testTable;
public TestController() {
}
#PostConstruct
public void init() {
//basic initialization
testTable = new TestTable();
}
//rest of your code...
}
With this change, JSF will be able to set the values from the <h:form> into the bounded fields. Note that JSF code will just invoke the necessary getters and setters accordingly to the defined in your EL, it won't create a new instance of the bounded fields. The getters are invoked when generating the view and the setters when submitting the form to the server.
More info:
Creating new entities while enabling injection
Why use #PostConstruct?
StackOverflow Expression Language wiki
Related
I have below repository model class
class Model {
#Column(name="id")
private static Integer id;
#Column(name="column-to-be-converted")
#Convert(converter=Converter.class)
private static String columnToBeConverted;
#Column(name="apply-converter")
private static boolean applyConverter;
// Getters and Setters
}
Below is the Converter class
#Component
#Converter
public class PasswordConverter implements AttributeConverter<String, String> {
#Override
public String convertToDatabaseColumn(String rawData) {
// logic goes here
}
#Override
public String convertToEntityAttribute(String convertedData) {
// logic goes here
}
}
I want to apply #Convert annotation to the field columnToBeConverted only if the field applyConverter is set to true
I tried investigating if the model object can be passed to Converter Class as argument or with using #Conditional
Please suggest how can this be achieved
Thank you!
I want to store a property into the database as a Long, but use the object with helper methods in the code.
However the object type is a custom type I have that has an internal value (a long) that I want to store to the database.
public final class MyBean extends Number implements Serializable, Comparable<MyBean>
{
private long myValue;
public MyBean(Long value) { this.myValue = value; }
// Other helper methods and overrides
public MyBean valueOf(Long data)
{
return new MyBean(data);
}
#Override
public String toString()
{
return String.valueOf(myValue);
}
}
This is how I am using it:
#Entity
#Table(name = "mybeans")
public class MyBean implements Serializable
{
private static final long serialVersionUID = 1L;
MyBean myBean;
#Id
#Column(name = "mybean", nullable = false)
public MyBean getMyBean() { return myBean; }
public void setMyBean(MyBean value) { this.myBean = value; }
}
Deserializing this object calls toString and works fine (jax-rs/jersey). But when I try to pull it out of the database using my EJB, the error I get is:
The object [1,427,148,028,955], of class [class java.lang.Long], could
not be converted to [class com.MyBean]
Saving it produced the error
Can't infer the SQL type to use for an instance of com.MyBean. Use
setObject() with an explicit Types value to specify the type to use.
Which makes sense.
But what methods can I add in to male the EJB get the long as the value and use the long to set up a new object?
ANSWER:
Making the class #Embeddable and adding the following attributes worked.
#Embedded
#AttributeOverrides({
#AttributeOverride(name="value", column=#Column(name="mybean"))
})
(I didn't add EmbeddedId because I added a serial primary key id and just made this a column)
The one caveat is that it won't work with dynamic weaving. I had to add
<property name="eclipselink.weaving" value="static"/>
to my persistence.xml
You can try making MyBean an Embeddable to use that as an EmbeddedId, something like this:
#Embeddable
public final class MyBean extends Number implements Serializable, Comparable<MyBean> {
private Long myValue;
public MyBean(Long myValue) {
this.myValue = myValue;
}
// Other helper methods and overrides
public MyBean valueOf(Long data) {
return new MyBean(data);
}
#Override
public String toString() {
return String.valueOf(myValue);
}
}
In your entity, MyBean will be an EmbeddedId and will look like this:
#Entity
#Table(name = "mybeans")
public class MyEntity implements Serializable {
private static final long serialVersionUID = 1L;
private MyBean myBean;
#EmbeddedId
#AttributeOverride(name="myValue", #Column(name="mybean_id"))
public MyBean getMyBean() {
return myBean;
}
public void setMyBean(MyBean myBean) {
this.myBean = myBean;
}
}
Adjust MyBean as you need, such as making Transient some attributes.
i want to pass my form value into my managed bean in order to process it but i always got a null value when i try to retrieve the value in my action method
My bean
#ManagedBean(name="datas")
#SessionScoped
public class Datas implements Serializable {
private static final long serialVersionUID = 1L;
private String ID_primary;
public Datas(){
}
public Datas (String ID_primary){
this.ID_primary=ID_primary;
}
public String getID_primary() {
return ID_primary;
}
public void setID_primary(String ID_primary) {
this.ID_primary= ID_primary;
}
public void process() {
Map<String, String> request=FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
String value = request.get("ID_primary"); // always return null
System.out.println("ID" + value);
}
}
My form
<h:form>
<div align="left">
<h:inputText id="ID_primary" name="ID_primary" value="#{datas.ID_primary}" />
</div>
..........
<div align="right">
<h:commandButton action="#{datas.process()}" value="Create" type="submit" />
</div>
</h:form>
Thank you very much for your help
You have two different form elements, when you click commandButton in the bottom form, values from the top form are not send with the request.
You can have tags like div inside a form, so you can make on big form with divs inside if it is the reason why you have have split them.
Also add #ManagedProperty annotation to ID_primary field:
public class Datas implements Serializable {
private static final long serialVersionUID = 1L;
#ManagedProperty(value = "#{Datas.ID_primary}")
private String ID_primary;
[..]
EDIT:
Ok, my bad, I have not looked at the code carefully. In ManagedBean with ManagedProperty this property will be set automatically by JSF, so you can read it like this:
public void process() {
System.out.println("ID" + getID_primary());
}
I am setting a value in the login-bean when the user logs-in
using
--Login-bean
setMailNickname(mailnickname);
And in the info page I am able to retrieve the same value using
--InfoPage
<h:inputText value="#{login.mailNickname}" />
Now on the info page I am taking some more info from the user and saving all of them in the database, As one of the value is from the login form bean it is prepopulating on the Info-page but how to assign the same value to the info-page bean variable-
InfoBean.mailNickname
so that it can be saved into the database with the other fields which the user provides.
How can I assign the value to the infopage bean variable?
You can inject LoginBean into InfoBean, so that you can have a reference to its fields. As I understand one of your beans is at least #SessionScoped. You didn't provide that information, so I'd go as far as to guess that LoginBean is used for logging into your application or something like that and InfoBean to hold that information for future reference. Following that chain of thinking your InfoBean would look like that:
#ManagedBean
#SessionScoped
public class InfoBean {
private String mailNickname;
public String getMailNickname() {
return mailNickname;
}
public void setMailNickname(final String mailNickname) {
this.mailNickname = mailNickname;
}
// other fields, methods...
}
and your LoginBean then would hold reference to session-scoped InfoBean:
#ManagedBean
#ViewScoped
public class LoginBean {
private String mailNickname;
public String getMailNickname() {
return mailNickname;
}
public void setMailNickname(final String mailNickname) {
this.mailNickname = mailNickname;
}
#ManagedProperty("#{infoBean}")
private InfoBean infoBean;
public void setInfoBean(final InfoBean infoBean) {
this.infoBean = infoBean;
}
/** Method you use for populating */
public void populateInput(final String mailNicknameFromDb) {
setMailNickname(mailNicknameFromDb);
infoBean.setMailNickname(mailNicknameFromDb);
}
}
Remember about getters and setters for those fields as well as setter for managedProperty and be careful about scopes (you can't for example inject request-scoped bean into application-scoped bean, because the request-scoped one would probably not exist yet when creating application-scoped one).
When or where do entities get created?
Do they get created when the XHTML page loads and accesses the entities via the managed bean?
Or do they get automatically created in the managed bean?
Do we need to manually create it from the managed bean's constructor?
Please see the code below (some necessary code might not have been copied.)
The entity would be:
public class PersonalInfo implements Serializable {
#Size(max = 50)
#Column(name = "FIRST_NAME", length = 50)
private String firstName;
// some getters and setters
}
the web page would be:
<h:form>
<h:outputText value="first name"/>
<h:inputText value="#{personalInforController.personalInfo.firstName}" />
<h:commandButton value="hit me"
action="#{personalInforController.create}"
immediate="true"/>
</h:form>
and the backing bean would be:
#Named(value = "personalInfoController")
#SessionScoped
public class PersonalInforController {
#EJB
PersonalInfoFacade ejbFacade;
PersonalInfo personalInfo;
String defaultPage = "index";
public String create() {
try {
ejbFacade.create(personalInfo);
return "prepareCreate";
} catch (Exception e) {
return "success";
}
}
}
In the example code given, the create action indeed doesn't seem to be able to work. The entity must be created by the backing bean before that.
If it's a simple entity, either the constructor or an #PostConstruct method would work. For instance:
#Named(value = "personalInfoController")
#SessionScoped
public class PersonalInforController {
#EJB
PersonalInfoFacade ejbFacade;
PersonalInfo personalInfo;
String defaultPage = "index";
#PostConstruct
public void init() {
personalInfo = new PersonalInfo();
}
public String create() {
try {
ejbFacade.create(personalInfo);
return "prepareCreate";
} catch (Exception e) {
return "success";
}
}
Some notes about the code. It's highly suspicious, and most likely plain wrong, to declare your bean to be #SessionScoped. If personalInfo is being edited in two tabs or windows you'll be in a world of hurt. I suggest making your bean #ViewScoped (for CDI, there's a separate extension made by the Seam3 that enables this, if you can't/won't use this extension consider using #ManagedBean instead of #Named).
Also, you might want to declare your instance variables to be private and give ejbFacade a better name (e.g. personalInfoFacade). I also doubt whether immediate is necessary on the commandButton, and since the outputText is obviously a label for the given inputText, you might want to consider using outputLabel and the for attribute.