I am trying out some examples from Beginning Java EE6 with GlassFish3 .So , i created an entity class that basically looks like this ...
#Entity
#Table(name="Book")
public class Book implements Serializable
{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(nullable=false)
private String name;
#Column(nullable=false)
private String isbn;
private String description;
public Book()
{
// Empty constructor to facilitate construction.
System.out.println("The variables have not been initialized...Please initialize them using the Setters or use the provided constructor");
}
public Book(String name, String isbn, String description) {
this.name = name;
this.isbn = isbn;
this.description = description;
}
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
#Override
public String toString() {
return this.name + " - " + this.isbn;
}
#PrePersist
public void printPrePersist(){
System.out.println("Persisting the book "+this.name);
}
#PostPersist
public void printPostPersist(){
System.out.println("Persisted the book "+this.name);
}
}
and i tried to persist it like this ...
public class MainClass
{
public static void main(String[] args){
Book book = new Book("Effective Java","ISBN - 1234415","A very good book on Java");
Book book2 = new Book("Learning Java EE","ISBN - 1233415","A good book for Java EE beginners");
// These are the necessary classes
EntityManagerFactory emf = Persistence.createEntityManagerFactory("PersistenceAppPU");
EntityManager em = emf.createEntityManager();
// Persist the book here
EntityTransaction etx = em.getTransaction();
etx.begin();
em.persist(book);
em.persist(book2);
etx.commit();
em.close();
emf.close();
System.out.println("The two books have been persisted");
}
}
It persists , but when i run , i see an output like ...
The variables have not been initialized...Please initialize them using the Setters or use the provided constructor
Persisting the book Effective Java
The variables have not been initialized...Please initialize them using the Setters or use the provided constructor
Persisting the book Learning Java EE
Persisted the book Learning Java EE
Persisted the book Effective Java
The variables have not been initialized...Please initialize them using the Setters or use the provided constructor
The variables have not been initialized...Please initialize them using the Setters or use the provided constructor
The variables have not been initialized...Please initialize them using the Setters or use the provided constructor
The variables have not been initialized...Please initialize them using the Setters or use the provided constructor
[EL Info]: 2012-05-10 12:01:19.623--ServerSession(17395905)--file:/C:/Users/raviteja.s/Documents/NetBeansProjects/PersistenceApp/src/_PersistenceAppPU logout successful
The two books have been persisted
I dont understand , why there are so many default constructor calls when , there is not one made by me ... ?
Could somebody explain me how the flow is in the sample that i have ?
JPA uses a constructor with no arguments in order to instantiate your Entities, and then bind fields in those entities to the correspondent mapped tables and columns.
Those output you see are the calls that JPA does for you every time it manipulates your entities.
Related
please help me with this one. I have a very simple crud project with a student table in oracle DB(ID,name,age,email) in springboot and all i want to know is get a student with a method in the jpa repository that calls a stored procedured. when run the project i got an error PLS-00221 is not a procedure or is undefined.
--stored procedure
CREATE OR REPLACE FUNCTION
findstudentbyid
RETURN STUDENT%ROWTYPE
IS
estudiante STUDENT%ROWTYPE;
BEGIN
SELECT *
INTO estudiante
FROM STUDENT
WHERE ID=1;
RETURN estudiante;
END findstudentbyid;
//Entity in sprongboot project
#Entity
#Table
#NamedStoredProcedureQueries({
#NamedStoredProcedureQuery(
name = "findstudentbyid",
procedureName = "findstudentbyid"
)
})
public class Student {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
//Private variables
private Long ID;
private String name;
private Number age;
private String email;
//Constructor
protected Student(){}
public Student(String name , Number age , String email){
this.name = name;
this.age = age;
this.email = email;
}
public Long getID() {
return ID;
}
public String getName() {
return name;
}
public Number getAge() {
return age;
}
public String getEmail() {
return email;
}
}
//JPA CRUD REPOSITORY
public interface StudentRepository extends CrudRepository<Student,Long>{
#Procedure(name = "findstudentbyid")
Iterable<Student> findstudentbyid();
}
You create a function but not a stored procedure.
These objects are different for DB and JPA, try to change your create function to create procedure or change the procedure's call to the function's call signature.
Also, see here for more info about JPA and function call.
I have two classes of Authors and Books:
public class Authors extends RealmObject {
#PrimaryKey
private String url_base;
private RealmList<Books> books;
... getters & setters...
public RealmList<Books> getBooks() {
return books;
}
public void setBooks(RealmList<Books> books) {
this.books = books;
}
}
public class Books extends RealmObject {
#PrimaryKey
private String url_base;
private Authors author;
... getters & setters...
public Authors getAuthor() {
return author;
}
public void setAuthor(Authors author) {
this.author = author;
}
}
Perform inserts:
Authors author = new Authors();
author.setUrl_base("url_base")
Books book = new Books();
book.setUrl_base("lala");
book.setAuthor(author);
author.getBooks().add(book); // error comes here
realm.beginTransaction();
realm.copyToRealmOrUpdate(author);
realm.commitTransaction();
And the program gives java.lang.NullPointerException.
Error line : author.getBooks().Add (book);
What could be wrong? I ask your help.
You haven't set the books member for your author object (as books is not initialized it is null) so getBooks() will return a null.
Make sure books is initialized before using it :
public class Authors extends RealmObject {
#PrimaryKey
private String url_base;
private RealmList<Books> books = new RealmList<Books>(); // An empty unmanaged books list.
... getters & setters...
or use the setter method (though initializing it on construction will be more correct in this case):
Authors author = new Authors();
author.setUrl_base("url_base")
author.setBooks(new RealmList<Book>());
UPDATE:
As #AndreyAtapin correctly noted in the solution above the list will be unmanaged. If you want a managed list pass the required arguments as specified in the RealmList api but whatever you choose the books list must be initialized before you start manipulating it
According to Realm docs you should instantiate entity objects with special factory method:
realm.beginTransaction();
Authors author = realm.createObject(Authors.class);
author.setUrl_base("url_base")
Books book = realm.createObject(Books.class);
book.setUrl_base("lala");
book.setAuthor(author);
author.getBooks().add(book); // error comes here
realm.commitTransaction();
When you instantiate your entities with constructor, obviously all fields are null by default:
public class Authors extends RealmObject {
#PrimaryKey
private String url_base; // = null
private RealmList<Books> books; // = null
... getters & setters...
}
PS: By the way, using variables names url_base contradicts the Java coding conventions. You better call it urlBase (setUrlBase/getUrlBase accordingly).
I have a Base Class.
#Data
class BaseDocument{
String id;
String name;
//Other fields
}
Say I have many classes that extends BaseDocument one below.
class NoteDocument extends BaseDocument{
String description;
Long lastModifiedDate;
//etc
}
It does not make sense to me to send entire document to UI in some cases. Most of the cases I need only id and name.
So for every document I have a VO class.
#Data
class BaseVO {
private String id;
private String name;
}
#Data
class NoteVO extends BaseVO{
//Nothing here now
}
And in NoteDocument I have.
public NoteVO getVo(){
Assert.notNull(getId());
NoteVO noteVo = new NoteVO();
noteVo.setName(getName());
noteVo.setId(getId());
return noteVo;
}
Now I have to copy this method in all the classes that extends BaseDocument.
Instead, I changed my BaseDocument like below.
#Data
class BaseDocument<V extends BaseVO>{
String id;
String name;
public V getVo(Class className) {
Assert.notNull(getId());
V vo = null;
try {
vo = (V) className.newInstance();
vo.setName(getName());
vo.setId(getId());
} catch (IllegalAccessException|InstantiationException e){
e.printStackTrace();
}
Assert.notNull(vo);
return vo;
}
}
I am new to generics. My first question, is this a good practice. Are there any problems in using reflection to create instance, any performance issues? Is there any better way to do achieve (write less code) this.
Edit: Suppose I need to display note in UI, Along with note I need to display name of the User who created note. I am using mongodb, when I save the note I also save UserVO in note, which will have user id and name of the user. If I save only user id while saving the note, I will have to do one more query to get the name of user while displaying. I want to avoid this.
Do not use reflection; use inheritance and maybe covariant return types instead. It will be faster, clearer, more precise, and easier to maintain. You may also find it useful to add methods to populate your VOs incrementally. I didn't come up with a clean way to apply generics to this situation, but I don't think you need them:
class BaseVO {
String id;
String name;
void setId(String id) {
this.id = id;
}
void setName(String name) {
this.name = name;
}
}
class NoteVO extends BaseVO {
// ...
}
#Data
class BaseDocument {
String id;
String name;
//Other fields
protected void populateBaseVO(BaseVO vo) {
vo.setId(id);
vo.setName(name);
}
public BaseVO getVO() {
BaseVO vo = new BaseVO();
populateBaseVO(vo);
return vo;
}
}
#Data
class NoteDocument extends BaseDocument {
String description;
Long lastModifiedDate;
// ....
protected void populateNoteVO(NoteVO vo) {
populateBaseVO(vo);
// ...
}
public NoteVO getVO() {
NoteVO vo = new NoteVO();
populateNoteVO(vo);
return vo;
}
}
I am using MyBatis to do a simple select.
Assume we have the following classes:
class Book {
private String bookName;
public Book(String bookName){
this.bookName = bookName;
}
public String getBookName(){
return bookName;
}
}
class Student {
private String studentName;
private Book book;
public Student(){}
// getters and setters
}
I have an annotation on a method that returns a Student object.
#Select("Select studentName, book from Students")
My Issue is that book is always null. I was under the assumption MyBatis will call the constructor with that JDBC type (in this case String) to populate book. What am I missing or doing incorrectly?
One option is
Use #ConstructorArgs annotations to explicitly call Constructor method.
#Select("Select studentName, book from Students")
#ConstructorArgs(value = {
#Arg(column = "studentName", javaType=java.lang.String.class),
#Arg(column = "book", javaType = java.lang.String.class)
})
and pass them to Student constructor, which calls Book constructor.
I'm still struggling with changing my Spring Application to use Hibernate with JPA to do database activities. Well apparently from a previous post I need an persistence.xml file. However do I need to make changes to my current DAO class?
public class JdbcProductDao extends Dao implements ProductDao {
/** Logger for this class and subclasses */
protected final Log logger = LogFactory.getLog(getClass());
public List<Product> getProductList() {
logger.info("Getting products!");
List<Product> products = getSimpleJdbcTemplate().query(
"select id, description, price from products",
new ProductMapper());
return products;
}
public void saveProduct(Product prod) {
logger.info("Saving product: " + prod.getDescription());
int count = getSimpleJdbcTemplate().update(
"update products set description = :description, price = :price where id = :id",
new MapSqlParameterSource().addValue("description", prod.getDescription())
.addValue("price", prod.getPrice())
.addValue("id", prod.getId()));
logger.info("Rows affected: " + count);
}
private static class ProductMapper implements ParameterizedRowMapper<Product> {
public Product mapRow(ResultSet rs, int rowNum) throws SQLException {
Product prod = new Product();
prod.setId(rs.getInt("id"));
prod.setDescription(rs.getString("description"));
prod.setPrice(new Double(rs.getDouble("price")));
return prod;
}
}
}
Also my Product.Java is below
public class Product implements Serializable {
private int id;
private String description;
private Double price;
public void setId(int i) {
id = i;
}
public int getId() {
return id;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("Description: " + description + ";");
buffer.append("Price: " + price);
return buffer.toString();
}
}
I guess my question would be,
How would my current classes change after using Hibernate + JPA with an Entity Manager
Did you check the section 12.6. JPA of the Chapter 12. Object Relational Mapping (ORM) data access in the official documentation? Everything you need to know is discussed there.
If this is an option, you should extend the JpaDaoSupport base class, it provides convenient methods like get/setEntityManagerFactory and getJpaTemplate() to be used by sublasses. If not, then get a EntityManagerFactory injected and use it to create a JpaTemplate. See the section 12.6.2. JpaTemplate and JpaDaoSupport for more details on this.
Also have a look at Getting Started With JPA in Spring 2.0 for a more complete sample (the blog post is a bit old but is not really outdated) that will show you how to rewrite the methods of your DAO.
Moreover, I suggest you to read this article: Generic DAO with Hibernate and Spring AOP, before deciding your design.