need Spring Data JPA resource entry to make one many rest call - rest

Using Spring Data jpa and Spring Data Rest I could able to get basic CRUD operations to work. But I am facing problem with one to many (owner -> car(s)) relationship. Can any one help me in this.
Owner.java
#Entity
#Table(name = "OWNER")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Owner implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "name")
private String name;
#Column(name = "age")
private Integer age;
#OneToMany(mappedBy = "owner")
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Car> cars = new HashSet<>();
}
OwnerResource.java
#RestController
#RequestMapping("/api")
public class OwnerResource {
private final Logger log = LoggerFactory.getLogger(OwnerResource.class);
#Inject
private OwnerRepository ownerRepository;
#RequestMapping(value = "/owners",
method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public ResponseEntity<Owner> create(#RequestBody Owner owner) throws URISyntaxException {
log.debug("REST request to save Owner : {}", owner);
if (owner.getId() != null) {
return ResponseEntity.badRequest().header("Failure", "A new owner cannot already have an ID").body(null);
}
Owner result = ownerRepository.save(owner);
return ResponseEntity.created(new URI("/api/owners/" + result.getId()))
.headers(HeaderUtil.createEntityCreationAlert("owner", result.getId().toString()))
.body(result);
}
#RequestMapping(value = "/owners",
method = RequestMethod.PUT,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public ResponseEntity<Owner> update(#RequestBody Owner owner) throws URISyntaxException {
log.debug("REST request to update Owner : {}", owner);
if (owner.getId() == null) {
return create(owner);
}
Owner result = ownerRepository.save(owner);
return ResponseEntity.ok()
.headers(HeaderUtil.createEntityUpdateAlert("owner", owner.getId().toString()))
.body(result);
}
#RequestMapping(value = "/owners",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public ResponseEntity<List<Owner>> getAll(#RequestParam(value = "page" , required = false) Integer offset,
#RequestParam(value = "per_page", required = false) Integer limit)
throws URISyntaxException {
Page<Owner> page = ownerRepository.findAll(PaginationUtil.generatePageRequest(offset, limit));
HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/owners", offset, limit);
return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
}
#RequestMapping(value = "/owners/{id}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public ResponseEntity<Owner> get(#PathVariable Long id) {
log.debug("REST request to get Owner : {}", id);
return Optional.ofNullable(ownerRepository.findOne(id))
.map(owner -> new ResponseEntity<>(
owner,
HttpStatus.OK))
.orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));
}
}
OwnerRepository.java
/**
* Spring Data JPA repository for the Owner entity.
*/
public interface OwnerRepository extends JpaRepository<Owner,Long> {
}
The basic crud operation is working fine for Owner. But now I need to get all cars of a particular owner for that I need to add one rest call entry in OwnerResource.java and a method entry in OwneRepository.java. I tried different ways but getting many errors and is not working. The following is what I tried.
In OwnerRepository.java
Owner findAllByOwnerId(Long id);//But eclipse shows error here for this method
In OwnerResource.java
//Get All Cars
#RequestMapping(value = "/{id}/cars",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public ResponseEntity<Owner> getAll(#PathVariable Long id) {
log.debug("REST request to get All Cars of the Owner : {}", id);
return Optional.ofNullable(ownerRepository.findAllByOwnerId(id))
.map(owner -> new ResponseEntity<>(
owner,
HttpStatus.OK))
.orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));
}
But these two changes are not working out. I am beginner to spring data jpa and spring data rest. Can any one help me in correcting these two so that I can get all cars of the owner.

I believe it shows an error because the findAll returns a different type of object: List, Page, etc...
Try this:
List<Owner> findAllByOwnerId(#Param("id") Long id);
That will return you a list of objects. If you want to return with pagination, than you need this instead:
Page<Owner> findAllByOwnerId(#Param("id") Long id, Pageable pageable);
I hope this helps, let me know how it works for you.

Related

How to auto increment mongo db in Spring Boot?

I try simple CRUD in Spring Boot with Mongodb. I have problem with id number. How can I auto increment id. I tried but couldn't do it
Is there any simple auto increment way?
Controller
#Autowired
EmployeeRepo repo;
#RequestMapping(value = "home", method = RequestMethod.GET)
public String getHomePage(Model model) {
Employee employee = new Employee();
employee.setId(1);
employee.setName("deniz");
employee.setPassword("123");
repo.save(employee);
...
Employee
#Document(collection = "Employee")
public class Employee {
#Id
private long id;
private String name;
private String password;
// getter and setter
public long getNextSequenceId(String key) {
Query query = new Query(Criteria.where("_id").is(key));
Update update = new Update();
update.inc("seq", 1);
FindAndModifyOptions options = new FindAndModifyOptions();
options.returnNew(true);
SequenceId seqId =
mongoOperation.findAndModify(query, update, options, SequenceId.class);
return seqId.getSeq();
}

Exception when selecting specific columns using Hibernate and Spring Data JPA

I have a table that has a bytea column (named 'pdf') and I don't want to always select it, specially when I'm returning a list from the database, due to performance issues.
I use native queries with spring data inside the repository to solve these types of situations before (when I used eclipselink), but with Hibernate, if I don't write all the columns in the query, it throws an exception.
For test purposes, I'm trying to select only the id from the User and I still get the exception.
Example: "SELET user.id FROM user WHERE user.id = '1'"
It throws an exception saying that it did not find name in the ResultSet, if I put name in the SQL, it then says age was not found and so on, until I have to write all the columns in the SQL.
Thanks in advance for any help.
What I have tried already:
Updating/Downgrading Hibernate and Spring Data with no luck.
Creating a new entity with only the columns I need, works, but it's a messy solution for me.
Maybe the problem is the combination of the frameworks I use and the way I use them, if someone wants, I could try to upload my whole project structure.
My code:
Entity
#Entity
#Table(name = "user", schema = "portal")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#Column(name = "pdf")
private byte[] pdf;
#Column(name = "name")
private String name;
#Column(name = "age")
private Integer age;
public User() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public byte[] getPdf() {
return pdf;
}
public void setPdf(byte[] pdf) {
this.pdf = pdf;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
#Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Anexo)) {
return false;
}
Anexo other = (Anexo) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
#Override
public String toString() {
return "br.gov.to.secad.portal.domain.User[ id=" + id + " ]";
}
}
Service
#Service
#Transactional(readOnly = true)
public class UserService implements Serializable {
private static final long serialVersionUID = 1L;
#Autowired
private IUserRepository userRepository;
public UserService() {
}
public User findOne() {
return userRepository.findOneSQL();
}
}
Repository
public interface IUserRepository extends JpaRepository<User, Serializable>, JpaSpecificationExecutor {
#Query(value = "SELECT user.id FROM user WHERE user.id = '1'", nativeQuery = true)
public User findOneSQL();
}
The exception:
org.postgresql.util.PSQLException: The column name name was not found in this ResultSet.
Solution
The solution is using an array of Object when I want to select anything less than what I've mapped on my Entity class, thats the limitation of Hibernate that I now understand.
So basically, the method will return Object[] and then I can iterate each position and instantiate a new entity of User with these values.
Example:
#Query(value = "SELECT user.id FROM user WHERE user.id = '1'", nativeQuery = true)
public Object[] findOneSQL();
I have faced the same problem, I know it is late but well there is a solution that I found elegant.
By the Spring documentation you can declare an interface and from here take the fields you want, in my case it has been something similar to this.
The interface to minimize the fields:
public interface CountryMinify {
String getName();
String getNameTranslation();
}
And my JpaRepository
public interface PlanetRepository extends JpaRepository<Planet, Long> {
#Query(value = "select p.name_country as name, p.name_country_translation as nameTranslation from vm_planet p where gid = ?1", nativeQuery = true)
CountryMinify findByCode(String codeCountry);
}
Keep in mind that the columns should be called the same as gos getter. For example: column name_country -> AS name and the getter of the interface is getName()
Try this
#Query(value = "SELECT user.id FROM user WHERE user.id = '1'", nativeQuery = true)
Integer findOneSQL();
Call the method like so
Integer user = userRepository.findOneSQL();
Edit 1 :
Since you are using native query you wont be able to use Projections which is a great way of accessing only certain entity fields. There is a JIRA ticket which is still under investigation.
Solution
Return List from your repository like so
#Query(value = "SELECT user.id, user.name FROM user WHERE user.id = '1'", nativeQuery = true)
List<Object[]> findOneSQL();
Iterate over the list of Objects and get your specific columns.
List<Object[]> userNative = userRepository.findOneSQL();
for (Object[] obj : userNative) {
System.out.println("User id : " + obj[0]);
System.out.println("User Name : " + obj[1]);
}

Hibernate Envers - custom RevisionEntity - how to get record

I have written my custom RevisionEntity class to store additional data (for example username), like below:
#Entity
#RevisionEntity(AuditListener.class)
#Table(name = "REVINFO", schema = "history")
#AttributeOverrides({
#AttributeOverride(name = "timestamp", column = #Column(name = "REVTSTMP")),
#AttributeOverride(name = "id", column = #Column(name = "REV")) })
public class AuditEntity extends DefaultRevisionEntity {
private static final long serialVersionUID = -6578236495291540666L;
#Column(name = "USER_ID", nullable = false)
private Long userId;
#Column(name = "USER_NAME")
private String username;
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
I can see that all rows in database are correctly stored, REVINFO table contains also username.
I would like to query database to get detailed information from my custom RevisionEntity, like username.
How can I do it? Is there any supported API to get it?
Lets assume you know the identifier of the entity you're interested in the revision entity metadata for, you can easily query that information using the following approach:
final AuditReader auditReader = AuditReaderFactory.get( session );
List<?> results = auditReader.createQuery()
.forRevisionsOfEntity( YourEntityClass.class, false, false )
.add( AuditEntity.id().eq( yourEntityClassId ) )
.getResultList();
The returned results will contain an Object array, e.g. Object[] where results[1] will hold the revision entity instance which contains the pertinent information your wanting.
For more details, you can see the java documentation comments here
If you only have the revision number, you can access just the revision entity instance directly by:
// I use YourAuditEntity here because AuditEntity is actually an Envers class
YourAuditEntity auditEntity = auditReader
.findRevision( YourAuditEntity.class, revisionId );
For more details on the AuditReader interface, you can see the java documentation here

#OneToMany Entity Relationship not filling the list in the entity

I have asked a similar question these days, and after many many hours of trials and fails i find myself compelled to describe my problem from a different point of view.
So I have two entities, WaiterEntity and OrderEntity - as logic demands it, a waiter can have many orders, but an order just one waiter. When the method that persists orders is called, the given order is persisted correctly into the database. But when the waiter is asked about his orders with getOrders(), an empty list is returned. I tried to solve this like many tutorials tell, by (right after persisting the order) getting the list of orders from the waiter and adding the order to the list. Unfortunately there is very strange behaviour to observe: adding the line waiter.getOrders().add(order) somehow prevents or reverts the order to be persisted into the database. But when I try to get the waiter's orders, the all orders that previously were tried to persist appear correctly in the database, but at once the tables of WaiterEntity and OrderEntity become unreadable for JPA. (Although, I can still see the correct table contents through manually called SQL queries.) The only thing that helps is rebuilding the tables.
So maybe some properties of persistence.xml are wrong? The entity annotations are not correctly set up? Or the java code is invalid as I can't tell because I don't have much experience with JPA and GlassFish?
Here are the Entities:
#Entity
#XmlRootElement
#Table(name="WAITERENTITY")
public class WaiterEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval=true, fetch = FetchType.EAGER)
#JoinColumn(name = "waiter_id")
private List<OrderEntity> orders = new ArrayList<>();
... getters and setters
}
#Entity
#XmlRootElement
#Table(name="ORDERENTITY")
public class OrderEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long orderNumber;
#ManyToOne (cascade = CascadeType.ALL)
#JoinColumn (name = "table_id")
private TableEntity table_;
private int sumOfMoney = 0;
private boolean finalized = false;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval=true, fetch = FetchType.LAZY)
#JoinColumn(name = "order_id")
private List<OrderItemEntity> orderItems = new ArrayList<>();
#ManyToOne (cascade = CascadeType.DETACH)
#JoinColumn (name = "waiter_id")
private WaiterEntity waiter;
... getters and setters
}
The method to create orders:
public void create(OrderEntity e) {
WaiterEntity waiter = null;
if (e.getWaiter() != null) {
waiter = em.find(WaiterEntity.class, e.getWaiter().getId());
if (waiter != null) e.setWaiter(waiter);
}
if (e.getTable() != null) {
TableEntity table = em.find(TableEntity.class, e.getTable().getId());
if (table != null) e.setTable(table);
}
em.persist(e);
if (waiter != null) {
waiter = em.find(WaiterEntity.class, e.getWaiter().getId());
//waiter.getOrders().add(e);
}
}
As mentioned, the commented line only makes problems. Further on, without this line, everything in the database is as it should be, as in the foreign keys are set up right, but an obtained WaiterEntity has an empty list, regardless that in fact it has orders in its relationship in the database.
edit: The method that gets a waiter's orders:
public List<OrderEntity> findOrdersByWaiter(#QueryParam("id") long id) {
WaiterEntity waiter = em.find(WaiterEntity.class, id);
return waiter.getOrders();
}
As mentioned, in the situation when the commented line above is un-commented, the strage behaviour starts when calling findOrdersByWaiter(waiter.getId()).
Furthermore, no exceptions are thrown by GlassFish. It's like it just does nothing anymore when calling persitence methods that work with the tables of WaiterEntity and/or OrderEntity.
It would really help if someone more experienced told me what I am doing wrong. If further explanation or code snippets are needed for a better understanding of the situation, I will paste it here. Thanks in advance!
edit 2: (#DonovanMuller) First, a little explanation why there are different object types: I use web resources. The client program and server program communicate using JSON. Only the server knows entity models and persists them. The client does the following (I am not posting all it's methods, just the relevant ones):
IWaiterWebAppClient client = new IWaiterWebAppClient();
client.create(new WaiterBean("John Marston"));
client.create(new WaiterBean("Abigail Marston"));
WaiterBean waiter = client.findByNameSingle(WaiterBean.class, "John Marston");
int rnd = (int) Math.round(Math.random() * 100);
client.create(new TableBean(rnd));
TableBean table = client.findByNameSingle(TableBean.class, String.valueOf(rnd));
OrderBean order = new OrderBean(waiter);
order.setWaiter(null);
client.create(order);
client.create(new OrderBean(waiter, table));
System.out.println(waiter.getName() + "'s OrderBeans:\n" + client.findOrdersByWaiter(waiter.getId()));
while client is an instance of:
public class IWaiterWebAppClient {
private final WebTarget webTarget;
private final Client client;
private static final String BASE_URI = "http://localhost:8080/iWaiter_WebAppServer/webresources";
public IWaiterWebAppClient() {
client = javax.ws.rs.client.ClientBuilder.newClient();
webTarget = client.target(BASE_URI).path("iwaiter");
}
public void close() {
client.close();
}
public <T> void create(T bean) {
webTarget.path(getResourcePath(bean.getClass()))
.request()
.post(Entity.entity(bean,MediaType.APPLICATION_JSON + ";charset=UTF-8"));
}
public <T> T findByNameSingle(Class<T> type, String name) {
List<T> list = findByName(type, name);
return (!list.isEmpty() ? list.get(0) : null);
}
public <T> List<T> findByName(Class<T> type, String name) {
return webTarget.path(getResourcePath(type) + "/findbyname/{name}")
.queryParam("name", name).request(MediaType.APPLICATION_JSON)
.get(constructGenericTypeArrayList(type));
}
public List<OrderBean> findOrdersByWaiter(long id) {
List<OrderBean> list = webTarget.path("order/findbywaiter/{id}")
.queryParam("id", id).request(MediaType.APPLICATION_JSON)
.get(new GenericType<ArrayList<OrderBean>>() {});
return list;
}
private String getResourcePath(Class c) {
if (c.equals(EmployeeView.class)) return "employee";
if (c.equals(WaiterBean.class)) return "waiter";
if (c.equals(TableBean.class)) return "table";
if (c.equals(ItemBean.class)) return "availableitem";
if (c.equals(OrderBean.class)) return "order";
return "";
}
...
}
The fields, getters and setters of WaiterBean and WaiterEntity, as well as OrderBean and OrderEntity, are the same. The only difference is that the 'beans' don't have JPA annotations.
edit 3: (#DonovanMuller) The server is a resource class which methods represent HTTP methods (GET, POST, PUT, DELETE) and exchange information with JSON. The methods of the server have resource annotations, such as:
#GET #Path("order/findbywaiter/{id}")
#Produces("application/json")
public List<OrderEntity> findOrdersByWaiter(#QueryParam("id") long id) { ... }
edit 4: (#DonovanMuller) This is the main part of the web resource class that is responsible for persistence:
#Path("iwaiter")
#Stateless
public class IWaiterResource {
#PersistenceContext(unitName = "ZZZ_WebServicePU")
private EntityManager em;
#Context
private UriInfo context;
#POST #Path(PATH_WAITER)
#Consumes({"application/json", "application/xml"})
public void create(WaiterEntity e) { em.persist(e); }
#POST #Path(PATH_ORDER)
#Consumes({"application/json", "application/xml"})
public void create(OrderEntity e) {
WaiterEntity waiter = e.getWaiter();
em.persist(e);
if (waiter != null) {
waiter.getOrders().add(e);
}
}
#PUT #Path(PATH_WAITER)
#Consumes({"application/json", "application/xml"})
public void update(WaiterEntity e) { em.merge(e); }
#PUT #Path(PATH_ORDER)
#Consumes({"application/json", "application/xml"})
public void update(OrderEntity e) { em.merge(e); }
#DELETE #Path(PATH_WAITER)
#Consumes({"application/json", "application/xml"})
public void deleteWaiter(#QueryParam("id") long id) { em.remove(em.find(WaiterEntity.class, id)); }
#DELETE #Path(PATH_ORDER)
#Consumes({"application/json", "application/xml"})
public void deleteOrder(#QueryParam("id") long id) { em.remove(em.find(OrderEntity.class, id)); }
private <T> List<T> findAll(Class<T> type) {
CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
cq.select(cq.from(type));
return em.createQuery(cq).getResultList();
}
#GET #Path(PATH_WAITER)
#Produces({"application/json", "application/xml"})
public List<WaiterEntity> findAllWaiters() { return findAll(WaiterEntity.class); }
#GET #Path(PATH_ORDER)
#Produces({"application/json", "application/xml"})
public List<OrderEntity> findAllOrders() { return findAll(OrderEntity.class); }
#GET #Path(PATH_WAITER + "/" + PATH_FIND_BY_ID + "/{id}")
#Produces("application/json")
public WaiterEntity findWaiter(#PathParam("id") long id) { return em.find(WaiterEntity.class, id); }
#GET #Path(PATH_ORDER + "/" + PATH_FIND_BY_ID + "/{id}")
#Produces("application/json")
public OrderEntity findOrder(#PathParam("id") long id) { return em.find(OrderEntity.class, id); }
private <T> List<T> findByName(Class<T> type, String column, String searchTag) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<T> cq = cb.createQuery(type);
Root<T> root = cq.from(type);
cq.where(cb.equal(root.get(column), searchTag));
return em.createQuery(cq).getResultList();
}
#GET #Path(PATH_WAITER + "/" + PATH_FIND_BY_NAME + "/{name}")
#Produces("application/json")
public List<WaiterEntity> findWaitersByName(#QueryParam("name") String name) { return findByName(WaiterEntity.class, "name", name); }
#GET #Path(PATH_ORDER + "/" + PATH_FIND_BY_NAME + "/{name}")
#Produces("application/json")
public List<OrderEntity> findOrdersByName(#QueryParam("name") String name) { return findByName(OrderEntity.class, "orderNumber", name); }
#GET #Path("order/findbywaiter/{id}")
#Produces("application/json")
public List<OrderEntity> findOrdersByWaiter(#QueryParam("id") long id) {
WaiterEntity waiter = em.find(WaiterEntity.class, id);
return waiter.getOrders();
}
}
Your association is not mapped correctly. A bidirectional always has an owner side and an inverse side. In a OneToMany association, the inverse side must be the one side.
The inverse side does not specify how the association is mapped. It simply says: go look at the other side of the association to see how this association is mapped. This is done using the mappedBy attribute:
In Waiter:
#OneToMany(mappedBy = "waiter", cascade = CascadeType.ALL, orphanRemoval=true, fetch = FetchType.EAGER)
private List<OrderEntity> orders = new ArrayList<>();
In Order:
#ManyToOne(cascade = CascadeType.DETACH)
#JoinColumn(name = "waiter_id")
private WaiterEntity waiter;
The way you have done it, JPA considers waiter.orders and order.waiter as two independent associations, which, unfortunately, are mapped using the same join column. The two associations thus conflict with each other.
I moved this to an answer, as the comments were getting a bit long winded.
I haven't tested this but in your create(OrderEntity e) resource method (edit 4) your waiter reference is surely detached?
#POST #Path(PATH_ORDER)
#Consumes({"application/json", "application/xml"})
public void create(OrderEntity e) {
WaiterEntity waiter = e.getWaiter(); // <-- getting a reference to a detached entity. I.e. not managed by the entity manager
em.persist(e);
if (waiter != null) {
waiter.getOrders().add(e);
}
}
If you change it to the following, does it solve your problem?
#POST #Path(PATH_ORDER)
#Consumes({"application/json", "application/xml"})
public void create(OrderEntity e) {
em.persist(e);
Waiter waiter = e.getWaiter(); // <-- The reference to the persisted OrderEntity is now managed
if (waiter != null) {
waiter.getOrders().add(e);
}
}

Object: entity.ENTITY[ id=null ] is not a known entity type

this is a similar post to one I have seen before regarding this exception but I am utterly lost. I have yet to persist an entity to a database using JPA, although I have read from tables using it no problem. My setup is Netbeans 7.1 using Glassfish 3.1.1, EclipseLink is my persistence provider. I have a very simple scenario where I just want to test writing a persons name and age into the database and having the id auto increment. Its an MySql database with the fields: Id, FirstName and Age. Heres my code:
Web servlet to take in name and age from html form:
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String userPath = request.getServletPath();
if(userPath.equals("/addUser")){
//get request parameters from form
String name = request.getParameter("name");
String age = request.getParameter("age");
//set request attributes to be used by forwarded page
request.setAttribute("name", name);
request.setAttribute("age", age);
//create manager class to add person to database
Manager manager = new Manager();
manager.addPerson(name, age);
userPath = "/result";
}
// use RequestDispatcher to forward request internally
String url = "/WEB-INF/view" + userPath + ".jsp";
try {
request.getRequestDispatcher(url).forward(request, response);
} catch (Exception ex) {
ex.printStackTrace();
}
}
Manager class that takes in name and age, creates a person object and persists it.
public class Manager {
private static final String PERSISTENCE_UNIT_NAME = "FormPU";
private static EntityManagerFactory factory;
public Manager() {
}
public void addPerson(String name, String age) {
factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
EntityManager em = factory.createEntityManager();
Persons persons = new Persons();
persons.setName(name);
persons.setAge(age);
em.getTransaction().begin();
em.persist(persons);
em.getTransaction().commit();
em.close();
}
}
Persons entity class:
/**
*
* #author esmiala
*/
#Entity
#Table(name = "persons")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "Persons.findAll", query = "SELECT p FROM Persons p"),
#NamedQuery(name = "Persons.findById", query = "SELECT p FROM Persons p WHERE
p.id = :id"),
#NamedQuery(name = "Persons.findByFirstName", query = "SELECT p FROM Persons p
WHERE p.firstName = :firstName"),
#NamedQuery(name = "Persons.findByAge", query = "SELECT p FROM Persons p WHERE
p.age = :age")})
public class Persons implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#NotNull
#Column(name = "Id")
private Integer id;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 255)
#Column(name = "FirstName")
private String firstName;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 255)
#Column(name = "Age")
private String age;
public Persons() {
}
public Persons(Integer id) {
this.id = id;
}
public Persons(Integer id, String firstName, String age) {
this.id = id;
this.firstName = firstName;
this.age = age;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
#Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Persons)) {
return false;
}
Persons other = (Persons) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
#Override
public String toString() {
return "entity.Persons[ id=" + id + " ]";
}
}
Persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com
/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="FormPU" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/form</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties/>
</persistence-unit>
</persistence>
Note: I have also tried setting exclude-unlisted-classes tag to true and list the class seperately but that didn't work either.
The exception:
WARNING: StandardWrapperValve[Controller]: PWC1406: Servlet.service() for servlet
Controller threw exception
java.lang.IllegalArgumentException: Object: entity.persons[ id=null ] is not a
known entity type.
atorg.eclipse.persistence.internal.sessions.UnitOfWorkImpl.registerNewObject
ForPersist(UnitOfWorkImpl.java:4141)
atorg.eclipse.persistence.internal.jpa.EntityManagerImpl.
persist(EntityManagerImpl.java:368)
at manager.Manager.addPerson(Manager.java:36)
at controller.Controller.doPost(Controller.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:754)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1523)
...and so on. Any help would be greatly appreciated!
<exclude-unlisted-classes> doesn't work as you would expect - the very presence of this element in persistence.xml disables automatic discovery of #Entity classes, no matter what's inside it.
Also, #Entity(name="persons") is probably not what you want, use #Entity #Table (name="persons") instead.
So you say you can read the class fine, but get an error persisting a new instance?
Can you update an object that you read?
It seems you are having some kind of class loader issue. Somehow you have the class on your classpath twice, or have two different class loaders. The object you are passing to persist is from a different class loader than the one JPA is using. You can check the class loader of what was read, and of the object being persisted to see how they differ.
Have you redeployed you app, or hotdeployed? Does it work if you shut down/restart the server properly. Ensure you are closing your old EntityManagerFactory before redeploying.
Concerning youe concrete problem, try to see if this link helps.
Anyway, the way you are instantiating the EntityManager is not thread safe.
You can see here why. Or, better, you can use NetBeans' wizard for creating JPA controller classes from entity classes, and see how it injects the EntityManager:
#PersistenceContext
private EntityManager em;
See also that the controller classes (the equivalent of your Manager POJO) have the Stateless annotation. This is because you can safely inject an EJB (in this case the EntityManager) only in an object whose lifecycle is managed by the web container (see here for further reference about Accessing Enterprise Beans).