"org.hibernate.PersistentObjectException: detached entity" followed by application crash - spring

I am trying persist this entity:
#Entity
public class Produto extends Model {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
...
#OneToMany
#Fetch(FetchMode.SELECT)
#Cascade(CascadeType.ALL)
private List<Imagem> thumbnails;
...
}
through this form:
<table>
<tbody><tr>
<td>
<button type="button" onclick="add_single_imagem();" style="display: block;">
<img class="thumbnail" src="/images/icon_add_imagem.png" alt="adicionar icone">
<input type="file" accept="image/jpeg" class="image-uploader" id="thumbnails" style="display: none;" onchange="image_upload(this);" data-target="thumbnails" data-url="/imagem/upload" data-path="/imagem/download">
</button>
</td>
<td>
<div class="gallery" id="gallery">
<input type="hidden" name="thumbnails" value="3"><img class="thumbnail" id="image_3" src="/imagem/download/3"></div>
</td>
</tr>
</tbody></table>
which follow this "route":
controller
#RequestMapping(value = "/insert", method=RequestMethod.POST)
#ResponseBody
#PreAuthorize("hasPermission(#user, 'cadastra_'+#this.this.name)")
public void insert(#Valid E object, BindingResult result) {
serv.insert(object);
}
service
public void insert(E object) {
dao.insert(object);
}
dao
public void insert(E object) {
EntityManager entityManager = getEntityManager();
entityManager.getTransaction().begin();
entityManager.persist(object);
entityManager.getTransaction().commit();
entityManager.close();
}
PropertyEditor
public class ImagemEditor extends PropertyEditorSupport {
#Override
public void setAsText(String text) {
if (!text.equals("")) {
Integer id = Integer.parseInt(text);
ImagemService serv = new ImagemService();
org.loja.AppContextHolder.getContext().getAutowireCapableBeanFactory().autowireBean(serv);
Imagem imagem = serv.findBy("id", id);
setValue(imagem);
} else {
setValue(null);
}
}
}
But I am getting this error:
org.hibernate.PersistentObjectException: detached entity passed to persist: org.loja.model.imagem.Imagem
and when I try quit the application (with ctrl-c, I am running it with spring-boot), it crashes, stuck with this message:
2019-11-18 19:55:46.244 INFO 134572 --- [ Thread-3] .SchemaDropperImpl$DelayedDropActionImpl : HHH000477: Starting delayed evictData of schema as part of SessionFactory shut-down'
until I kill the process.
Anyone can give a hint of what's wrong here?

I managed to solve this issue changing the attribute configuration to that:
#OneToMany(fetch = FetchType.EAGER)
private Set<Imagem> thumbnails;
and with this html/thymeleaf code:
<table>
<tr>
<td>
<button type="button" onclick="add_single_imagem();" th:style="${command.icone}? 'display: none;' : 'display: block;'">
<img class="thumbnail" th:src="#{/images/icon_add_imagem.png}" alt="adicionar icone"/>
<input type="file" accept="image/jpeg" class="image-uploader" id="thumbnails" style="display: none;" th:attr="data-target=${'thumbnails'}, data-url=#{/imagem/upload}, data-path=#{/imagem/download}" onchange="image_upload(this);"/>
</button>
</td>
<td>
<div class="gallery" id="gallery">
<th:block th:each="img,stat : ${command.thumbnails}">
<input type="hidden" th:field="*{thumbnails}" th:value="${img.id}"/>
<img class="thumbnail" th:id="${'image_'+img.id}" th:src="#{/imagem/download/__${img.id}__}" th:alt="${command.nome}">
</th:block>
</div>
</td>
</tr>
</table>
Now this attribute is persisted alongside the entity without problems.

Related

I am getting an error 500, while i am trying to show all the products that exist in my database using SpringBoot

when i create a product and fill out the details in the create_product.html page when i click on add button, it should direct me to the Products.html page which I will show all the products but I am getting an error when I transferred me to the Products.html page. However, when i check my database table I found that the product had been added.
ProductController Class
#Controller
public class ProductsController {
//adding the service layer of the product
#Autowired
private ProductService productService;
#Autowired
private CategoriesRepository categoriesRepository;
public ProductsController(ProductService productService,CategoriesRepository categoriesRepository )
{
super();
this.productService = productService;
this.categoriesRepository = categoriesRepository;
}
// models
#ModelAttribute("category")
public List<Categories> initializeCategories(){
List<Categories> categories = categoriesRepository.findAll();
return categories ;
}
#ModelAttribute("product")
public Products products()
{
return new Products();
}
/////////////////////////////////// handllers
//request to list all the products
#RequestMapping("/products/all_products")
public String listProducts(Model model)
{
model.addAttribute("product",productService.getAllProducts());
return "Products/products";
}
//request to show the form to create a product // when u are accessing the http request u will access that one coz it will show the form and then the Save method will do the action
#GetMapping("/products/new/product")
public String createProductForm(Model model)
{
//Create product object
Products product = new Products();
model.addAttribute("product",product); // product is the object from products Entityclass
return "Products/create_product";
}
//request to create/save a product
#RequestMapping(value = "/products/create_product",method = RequestMethod.POST)
public String saveProduct(#ModelAttribute("product") Products product) // Products is the name of the Entity class and creating a productObjcet from it
{
productService.saveProduct(product);
return "redirect:/products/all_products";
}
#GetMapping("/products/edit/{id}")
public String editProductForm(#PathVariable long id, Model model)
{
model.addAttribute("product",productService.getProductById(id));
return "Products/edit_product";
}
//request to update product
#RequestMapping(value = "/products/update_product/{id}",method=RequestMethod.POST)
public String updateProduct(#PathVariable Long id, #ModelAttribute("product") Products product, Model model) // model Attribute is the data taken from the html file by the user
{
//get product from the db by id
Products existingProduct = productService.getProductById(id);
existingProduct.setProduct_id(id);
existingProduct.setProduct_name(product.getProduct_name());
existingProduct.setProduct_price(product.getProduct_price());
existingProduct.setProduct_category(product.getProduct_category());
existingProduct.setProduct_quantity(product.getProduct_quantity());
existingProduct.setProduct_Section(product.getProduct_Section());
existingProduct.setProduct_ExpDate(product.getProduct_ExpDate());
//updating the product
productService.updateProduct(existingProduct);
return "redirect:/products/all_products";
}
//request to Delete product
#GetMapping("/products/delete_product/{id}")
public String deleteProduct(#PathVariable long id)
{
productService.deleteProduct(id);
return "redirect:/products/all_products";
}
}
Categories Entity Class:
#Entity
#Data
public class Categories {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long categories_id;
private String categoryName;
#OneToMany(mappedBy = "product_category",fetch = FetchType.LAZY) //the name of the variable in the other class
private Set<Products> product_category = new HashSet<>();
public Categories(String categoryName, Set<Products> product_category) {
this.categoryName = categoryName;
this.product_category = product_category;
}
public Categories() {
}
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
}
Product Entity class :
#Entity
#Table(name = "Products")
#Data
public class Products {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long product_id;
private String product_name;
private BigDecimal product_price;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "categories_id") //the name of the column in the other class and that name will be a column in the class
private Categories product_category;
private String product_quantity;
private String product_Section;
private String product_ExpDate;
public Products()
{
super();
}
public Products(String product_name, BigDecimal product_price,String product_quantity,Categories product_category ,String product_Section,String product_ExpDate) {
this.product_name = product_name;
this.product_category = product_category;
this.product_price = product_price;
this.product_quantity = product_quantity;
this.product_Section = product_Section;
this.product_ExpDate = product_ExpDate;
}
ProductService Class:
#Service
public class ProductServiceImp implements ProductService {
//productRepository class
private ProductRepository productRepository;
public ProductServiceImp(ProductRepository productRepository) {
this.productRepository = productRepository;
}
#Override
public List<Products> getAllProducts() {
return this.productRepository.findAll();
}
#Override
public Products saveProduct(Products product) {
return this.productRepository.save(product);
}
#Override
public Products updateProduct(Products product) {
return this.productRepository.save(product);
}
#Override
public void deleteProduct(long id) {
this.productRepository.deleteById(id);
}
public Products getProductById(long id)
{
return productRepository.findById(id).get();
}
}
CreateProduct.html page:
<form th:action="#{/products/create_product}" method="post" th:object="${product}">
<div class="form-group">
<label class="control-label" for="product_name"> Product Name </label> <input
id="product_name" class="form-control" th:field="*{product_name}"
required autofocus="autofocus" />
</div>
<div class="form-group">
<label class="control-label" for="product_price"> Price </label> <input
id="product_price" class="form-control" th:field="*{product_price}" required
autofocus="autofocus" />
</div>
<div class="col-1.5">
<label th:for="category"> Category </label>
<select class="form-control form-control-sm" id="category" name="product_category">
<option value=""> Select Category </option>
<option th:each = "category: ${category}"
th:value="${category.categories_id}"
th:text="${category.categoryName}"
> <!--th:field="*{product_category}"-->
</option>
</select>
</div>
<br>
<div class="form-group">
<label class="control-label" for="product_quantity"> Quantity </label> <input
id="product_quantity" class="form-control" type="text"
th:field="*{product_quantity}" required autofocus="autofocus" />
</div>
<div class="form-group">
<label class="control-label" for="product_Section"> Section </label> <input
id="product_Section" class="form-control" type="text"
th:field="*{product_Section}" required autofocus="autofocus" />
</div>
<div class="form-group">
<label class="control-label" for="product_ExpDate"> Expire Date </label> <input
id="product_ExpDate" class="form-control" type="text"
th:field="*{product_ExpDate}" required autofocus="autofocus" />
</div>
<div class="form-group">
<button type="submit" class="btn btn-success">Save</button>
</div>
</form>
products.html page
<table class = "table table-striped table-bordered">
<thead class = "table-dark">
<tr>
<th> Category </th>
<th> Product Name </th>
<th> Product Price </th>
<th> Product Quantity </th>
<th> Product Section </th>
<th> Product Expiry Date </th>
<th> Edit </th>
<th> Delete </th>
</tr>
</thead>
<tbody>
<tr th:each = "product: ${product}"> <!-- this attribute to list up products -->
<td th:text="${product.product_category}" ></td>
<td th:text="${product.product_name}"></td>
<td th:text="${product.product_price}"></td>
<td th:text="${product.product_quantity}" ></td>
<td th:text="${product.product_Section}" ></td>
<td th:text="${product.product_ExpDate}" ></td>
<td> <center> <a th:href="#{/products/edit/{id}(id=${product.product_id})}" style="color: green"> Edit </a> </center> </td>
<td> <center> <a th:href="#{/products/delete_product/{id}(id=${product.product_id}) }" style="color: red"> Delete </a> </center> </td>
</tr>
</tbody>
</table>
FullTrace Error:
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Wed Oct 20 03:45:45 EDT 2021
There was an unexpected error (type=Internal Server Error, status=500).
No message available
java.lang.StackOverflowError
at com.mysql.cj.NativeSession.execSQL(NativeSession.java:696)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:930)
at com.mysql.cj.jdbc.ClientPreparedStatement.executeQuery(ClientPreparedStatement.java:1003)
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeQuery(ProxyPreparedStatement.java:52)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeQuery(HikariProxyPreparedStatement.java)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:57)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.getResultSet(AbstractLoadPlanBasedLoader.java:390)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeQueryStatement(AbstractLoadPlanBasedLoader.java:163)
at org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader.executeLoad(AbstractLoadPlanBasedLoader.java:104)
at org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer.initialize(AbstractLoadPlanBasedCollectionInitializer.java:87)
at org.hibernate.persister.collection.AbstractCollectionPersister.initialize(AbstractCollectionPersister.java:710)
at org.hibernate.event.internal.DefaultInitializeCollectionEventListener.onInitializeCollection(DefaultInitializeCollectionEventListener.java:76)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:99)
at org.hibernate.internal.SessionImpl.initializeCollection(SessionImpl.java:2163)
at org.hibernate.collection.internal.AbstractPersistentCollection$4.doWork(AbstractPersistentCollection.java:589)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:264)
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:585)
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149)
at org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:458)
at com.example.warehouseManagementSystem.Entities.Categories.hashCode(Categories.java:10)
at com.example.warehouseManagementSystem.Entities.Products.hashCode(Products.java:10)
at java.base/java.util.HashMap.hash(HashMap.java:340)
at java.base/java.util.HashMap.put(HashMap.java:612)
at java.base/java.util.HashSet.add(HashSet.java:221)
The problem is that you are using #Data from Lombok on your entity. Remove this and manually implement equals() and hashCode in a way that does not lead to a StackOverflowError. In most cases, you only want to check the primary key.
See https://www.wimdeblauwe.com/blog/2021/04/26/equals-and-hashcode-implementation-considerations/ for more info on how to correctly implement equals and hashcode.
See also https://thorben-janssen.com/lombok-hibernate-how-to-avoid-common-pitfalls/#Avoid_Data for more info on why you should be careful with Lombok and JPA/Hibernate.

How to make Search data using Spring boot

i am a beginner of spring boot framework.i want to work with search records using spring boot application. my index.html is loaded successfully when i enter the employee id on the employee id textbox and click search button relevant employee name result want to display the below textbox.but i don't know how to pass it .what i tired so so i attached below.
index.html
<form action="#" th:action="#{/search}" th:object="${employee}" method="post">
<div alight="left">
<tr>
<label class="form-label" >Employee ID</label>
<td>
<input type="hidden" th:field="*{id}" />
<input type="text" th:field="*{id}" class="form-control" placeholder="Employee ID" />
</td>
</tr>
</div>
<br>
<tr>
<td colspan="2"><button type="submit" class="btn btn-info">Search</button> </td>
</tr>
<div alight="left">
<tr>
<label class="form-label" >Employee Name</label>
<td>
<input type="text" th:field="*{ename}" class="form-control" placeholder="Employee Name" />
</td>
</tr>
</div>
</form>
Controller
#Controller
public class EmployeeController {
#Autowired
private EmployeeService service;
#GetMapping("/")
public String add(Model model) {
List<Employee> listemployee = service.listAll();
// model.addAttribute("listemployee", listemployee);
model.addAttribute("employee", new Employee());
return "index";
}
#RequestMapping("/search/{id}")
public ModelAndView showSearchEmployeePage(#PathVariable(name = "id") int id) {
ModelAndView mav = new ModelAndView("new");
Employee emp = service.get(id);
mav.addObject("employee", emp);
return mav;
}
}
Entity
#Entity
public class Employee {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Long id;
private String ename;
private int mobile;
private int salary;
public Employee() {
}
public Employee(Long id, String ename, int mobile, int salary) {
this.id = id;
this.ename = ename;
this.mobile = mobile;
this.salary = salary;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public int getMobile() {
return mobile;
}
public void setMobile(int mobile) {
this.mobile = mobile;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
#Override
public String toString() {
return "Employee [id=" + id + ", ename=" + ename + ", mobile=" + mobile + ", salary=" + salary + "]";
}
Repository
#Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}
It is easiest to create a dedicated form data object:
public class EmployeeSearchFormData {
private long employeeId;
// getter and setter
}
In the controller:
#Controller
public class EmployeeController {
#Autowired
private EmployeeService service;
#GetMapping("/")
public String add(Model model) {
model.addAttribute("employeeSearchFormData", new EmployeeSearchFormData());
return "index";
}
#PostMapping("/search")
public String doSearchEmployee(#ModelAttribute("employeeSearchFormData") EmployeeSearchFormData formData, Model model) {
Employee emp = service.get(formData.getEmployeeId());
model.addAttribute("employee", emp);
return "index";
}
}
Thymeleaf template:
<form action="#" th:action="#{/search}" th:object="${employeeSearchFormData}" method="post">
<div alight="left">
<tr>
<label class="form-label" >Employee ID</label>
<td>
<input type="text" th:field="*{employeeId}" class="form-control" placeholder="Employee ID" />
</td>
</tr>
</div>
<br>
<tr>
<td colspan="2"><button type="submit" class="btn btn-info">Search</button> </td>
</tr>
<div alight="left">
<tr>
<label class="form-label" >Employee Name</label>
<td>
<input type="text" th:field="${employee.ename}" class="form-control" placeholder="Employee Name" />
</td>
</tr>
</div>
</form>
Note the use of th:field="${employee.ename}" and not use *{...}. I also removed the hidden field as it does not seem needed to have it to me.
As an alternative, you can have the #PostMapping redirect to /employee/<id> if there is an endpoint available like that:
#PostMapping("/search")
public String doSearchEmployee(#ModelAttribute("employeeSearchFormData") EmployeeSearchFormData formData) {
return "redirect:/employee/" + formData.getEmployeeId();
}

Spring boot+Web mvc+JPA using CrudRepository giving issue on insert of a row using save method throwing EntityExistsException

Among CRUD operation Create is giving error of "A different object with the same identifier value was already associated with the session" Rest all (Read, Update and Delete) is working fine.
Im using oracle sql as database and there is one more entity of product with many to one mapping with categories class.
EntityClass
#Entity
public class Categories {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
public Categories() {
super();
}
public Categories(Integer id,String name) {
this.id=id;
this.name=name;
}
public Categories(String name) {
this.name=name;
}
//with setters and getters
}
JSP page
<body onload="document.getElementById('name').disabled = true;document.getElementById('hidden').disabled = true;">
<div align="center">
<h4>Add or Modify or Delete Categories</h4>
<form:form method="POST" action="/categories" modelAttribute="categories">
<table>
<tr>
<td><form:label path="name">Name</form:label></td>
<td>
<form:select path="name">
<form:option value="NONE" label="Select" />
<form:options items="${categoriesList}" />
</form:select>
</td>
</tr>
<tr>
<td>Operations</td>
<td>
<input type="radio" name="Ops" value="Add" checked="checked" onclick="document.getElementById('name').disabled = true; document.getElementById('newName').disabled = false;document.getElementById('hidden').disabled = true;">Add</input><br/>
<input type="radio" name="Ops" value="Modify" onclick="document.getElementById('name').disabled = false; document.getElementById('newName').disabled = false;document.getElementById('hidden').disabled = true;">Modify</input><br/>
<input type="radio" name="Ops" value="Delete" onclick="document.getElementById('name').disabled = false; document.getElementById('newName').disabled = true;document.getElementById('hidden').disabled = false;">Delete</input><br/>
</td>
</tr>
<tr>
<td>Name</td>
<td><input type="text" name="newName" id="newName"/>
<input type="hidden" id="hidden" name="newName" value="dummy"/>
</td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="Submit" /></td>
</tr>
</table>
</form:form>
</div>
</body>
Controller Class
#Controller
public class CategoriesController {
#Autowired
private CategoriesService cservice;
#RequestMapping(value = "/categories", method = RequestMethod.GET)
public ModelAndView categories() {
// view name model
ModelAndView modelAndView = new ModelAndView("categories", "categories", new Categories());
return modelAndView;
}
#RequestMapping(value = "/categories", method = RequestMethod.POST)
public String opsOnCategories(#ModelAttribute("categories") Categories cat,#RequestParam("Ops") String ops,#RequestParam("newName") String name)
{
if(ops.equals("Modify"))
{
cservice.modifyCategory(new Categories(Integer.parseInt(cat.getName()), name));
}else if(ops.equals("Add"))
{
cservice.addCategory(new Categories(name));
}else
{
cservice.deleteCategory(Integer.parseInt(cat.getName()));
}
return "categories";
}
#ModelAttribute("categoriesList")
public Map<String, String> getCategoryList() {
Map<String, String> categoriesList = new HashMap<String, String>();
List<Categories> ls=cservice.getAll();
for(int i=0;i<ls.size();i++)
{
categoriesList.put(ls.get(i).getId().toString(), ls.get(i).getName());
}
return categoriesList;
}
}
Can anyone please help on this.
Previous one due to which there was error
insert into CATEGORIES(ID,NAME) values (1,'Mobile');
insert into CATEGORIES(ID,NAME) values (2,'Laptop');
**Changes made to remove error*
insert into CATEGORIES(ID,NAME) values (hibernate_sequence.nextval,'Mobile');
insert into CATEGORIES(ID,NAME) values (hibernate_sequence.nextval,'Laptop');
My initial guess is that there something wrong with #Id #GeneratedValue with Oracle Database specifically.
There are couple of things that you can do:
1- Try to connect to any other Database type just to test the functionality - so that you can rule out what doesn't matter
2- Try to use the #org.springframework.data.annotation.Id alongside with the #Id of javax persistence
Something that look like this
#Id
#org.springframework.data.annotation.Id
private Integer id;
3- Create a class that Generates random Integer Ids and refer to it using the annotations (#GenericGenerator & #GeneratedValue)

Springboot Thymeleaf : How to format row according to a condition

I have a page that displays the list of all the journals available. I want to write a thymeleaf expression language that highlights the already subscribed journals using there journal id . So for all the subscribed journals the text for the hyper-link href should be "Unsubscribe" and vice verse if its not subscribed.
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head lang="en">
<title>TBD</title>
<!--/*/ <th:block th:include="fragments/headinc :: head"></th:block> /*/-->
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" />
</head>
<body>
<div class="container">
<h1 th:text="'Hello, ' + ${user.fullname} + '!'" />
<p>Manage your subscriptions here</p>
<form role="form" id="form-search" class="form-inline"
th:action="#{/subscriptions}" method="get">
<input type="text" class="form-control" id="filter" name="filter"
placeholder="Enter filter"></input>
<button type="submit" class="btn btn-default">
<span class="glyphicon glyphicon-search"></span> Search
</button>
<a th:href="#{/logout}" class="btn btn-link" role="button">Logout</a>
</form>
<div th:if="${not #lists.isEmpty(journals)}">
<form role="form" id="form-subscribe" th:action="#{/subscribe}"
method="post">
<input type="hidden" name="journalId" id="journalId" />
</form>
<table id="table" class="table">
<thead>
<tr>
<th>Subject</th>
<th>Filename</th>
<th>Tags</th>
<th>View</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr th:each="journal : ${journals}">
<td th:text="${journal.subject}">Id</td>
<td th:text="${journal.filename}">Product Id</td>
<td th:text="${journal.tags}">Description</td>
<td><a>View</a></td>
<td><a id="href"
th:href="'javascript:subscribe(\'' + ${journal.id} + '\');'">Subscribe</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
<script type="text/javascript">
function subscribe(journalId) {
$('#journalId').val(journalId);
$('#form-subscribe').submit();
}
</script>
<script type="text/javascript" th:inline="javascript">
/*<![CDATA[*/
$(document).ready(function() {
var modelAttributeValue = [[${subscriptions}]];
console.log(modelAttributeValue);
alert(modelAttributeValue);
var array = modelAttributeValue.split(';');
console.log(array);
alert(array);
});
/*]]>*/
</script>
</html>
Controller
#Controller
public class SubscriptionController {
#Autowired
private SubscriberService subscriberService;
#RequestMapping(value = "/subscribe", method = RequestMethod.POST)
String subscribe(Model model, #RequestParam("journalId") Integer journalId) {
JournalToken token = (JournalToken) SecurityContextHolder.getContext().getAuthentication();
Account user = (Account) token.getCredentials();
model.addAttribute("user", user);
Journal journal = this.subscriberService.findJournalById(journalId);
this.subscriberService.subscribeJournalForSubscriber(journal, user);
return "redirect:subscriptions";
}
#RequestMapping(value = "/subscriptions", method = RequestMethod.GET)
String list(Model model) {
JournalToken token = (JournalToken) SecurityContextHolder.getContext().getAuthentication();
Account user = (Account) token.getCredentials();
model.addAttribute("user", user);
ArrayList<Journal> journals = this.subscriberService.FindAllJournals();
model.addAttribute("journals", journals);
StringBuilder sub = new StringBuilder();
ArrayList<Subscription> subscribed = this.subscriberService.getSubscribedJournalsForSubscriber(user);
model.addAttribute("subscriptions", subscribed);
return "subscriptions";
}
}
Model subscriptions
#Entity
#Table(uniqueConstraints={#UniqueConstraint(columnNames={"userId", "journalId"})})
public class Subscription {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Version
private Integer version;
private Integer userId;
private Integer journalId;
public void setId(Integer id) {
this.id = id;
}
public Integer getId() {
return this.id;
}
public void setVersion(Integer version) {
this.version = version;
}
public Integer getVersion() {
return this.version;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public Integer getUserId() {
return this.userId;
}
public void setJournalId(Integer journalId) {
this.journalId = journalId;
}
public Integer getJournalId() {
return this.journalId;
}
}
you can change your arrayList subscribed to have only the ids of journals (more optimised).
So, in the controller you can have something like this
ArrayList<Integer> subscribed =
this.subscriberService.getSubscribedJournalsForSubscriber(user); //modify it so it returns the journals ids instead of the whole object(Subscription)
then in the thymeleaf change the anchor with something like this
<a id="href" th:href="'javascript:subscribe(\'' + ${journal.id} + '\');'">
<span th:if="${#lists.contains(subscriptions, journal.id) }" th:text="Unsubscribe"> Unsubscribe </span>
<span th:if="not ${#lists.contains(subscriptions, journal.id) }" th:text="Subscribe"> Subscribe </span>
</a>
Have a look at the documentation of thymeleaf http://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf.html
/*
* Check if element or elements are contained in list
*/
${#lists.contains(list, element)}
${#lists.containsAll(list, elements)}

org.springframework.web.util.NestedServletException Netbeans

I am using Spring Framework to develop a web app.
The problem is when i tried to add an article in my database It shows a NestedServlet exception. Can any one help me ?
This is my controler class :
#Controller
public class Controler {
ArticleFacadeLocal articleModel;
CategorieFacadeLocal categorieModel;
ConnexionFacadeLocal connexionModel;
public Controler(){
articleModel = new ArticleModel();
categorieModel = new CategorieModel();
connexionModel = new ConnexionModel();
}
#RequestMapping("/home.do")
public String home(HttpServletRequest request){
if(isConnected(request))
return addPage(request);
else return "page:login";
}
#RequestMapping("login.do")
public String login(HttpServletRequest request){
String login=request.getParameter("login");
String password=request.getParameter("password");
if(ConnexionModel.connect(login, password)){
request.getSession().setAttribute("login",login);
ServletContext application=request.getServletContext();
application.setAttribute("categories", categorieModel.findAll());
return addPage(request);}
else
request.setAttribute("error",true);
return "forward:/home.do";
}
#RequestMapping("logout.do")
public String logout(HttpServletRequest request) {
request.getSession(false).invalidate();
return "forward:/home.do";
}
#RequestMapping("articles.do")
public String list(HttpServletRequest request){
request.setAttribute("articles",articleModel.findAll());
return "page:articles";
}
#RequestMapping("addPage.do")
public String addPage(HttpServletRequest request){
request.setAttribute("categories", categorieModel.findAll());
return "page:add";
}
#RequestMapping("add.do")
public String add(HttpServletRequest request){
try{
Article a=getArticleFromView(request);
articleModel.create(a);
request.setAttribute("error", false);
}catch(Exception e){request.setAttribute("error", true);}
return "forward:/addPage.do";
}
#RequestMapping("modifyPage.do")
public String modiyPage(HttpServletRequest request){
int idArticle=Integer.parseInt(request.getParameter("idArticle"));
request.setAttribute("categories", categorieModel.findAll());
Article article = articleModel.find(idArticle);
request.setAttribute("article", article);
return "page:modify";
}
#RequestMapping("modify.do")
public String modify(HttpServletRequest request){
try{
Article a=getArticleFromView(request);
articleModel.edit(a);
return "forward:/articles.do";
}catch(Exception e){
request.setAttribute("error", true);
return "forward:/modifyPage.do";
}
}
#RequestMapping("searchPage.do")
public String searchPage(HttpServletRequest request){
return "page:search";
}
#RequestMapping("search.do")
public String search(HttpServletRequest request){
String libelle=request.getParameter("libelle");
request.setAttribute("article",articleModel.find(libelle));
return "page:search";
}
public boolean isConnected(HttpServletRequest request){
HttpSession session = request.getSession(false);//recupere une session sans la creer
return (session!=null && session.getAttribute("login")!=null);
}
public Article getArticleFromView(HttpServletRequest request){
Article a = new Article();
String libelle = request.getParameter("libelle");
String description = request.getParameter("description");
String prix = request.getParameter("prix");
String qte = request.getParameter("qte");
String categorie = request.getParameter("categorie");
a.setLibelle(libelle);
a.setDescription(description);
a.setPrix(Double.parseDouble(prix));
a.setQte(Integer.parseInt(qte));
a.setCategorie(new Categorie(categorie));
return a;
}
}
And this is my jsp file
<%#include file="include.jsp" %>
<form action="add.do" method="post">
<table align="center">
<tr >
<td>Libelle :
<td><input type="text" required="required" name="libelle"/>
</tr>
<tr >
<td>Description :
<td><input type="text" required="required" name="description">
</tr>
<tr>
<td>Prix :
<td><input type="text" required="required" name="prix">
</tr>
<tr>
<td>Quantité :
<td><input type="text" required="required" name="qte">
</tr>
<tr >
<td> Catégorie :
<td>
<select name="categorie" >
<c:forEach items="${categories}" var="c">
<option value="${c.idCategorie}"> ${c.libelleCategorie} </option>
</c:forEach>
</select>
</tr>
<tr align="center" >
<td colspan="2"><button type="submit" id="btn">Ajouter</button></td>
</tr>
</table>
</form>
<c:if test="${not empty error && error}"> <p style="color: red;"> Echec d'ajout de l'article </p></c:if>
<c:if test="${not empty error && not error}"> <p style="color: green;">Article ajouté avec succes </p></c:if>
This is error exception :
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.hibernate.AssertionFailure: null id in model.beans.Article entry (don't flush the Session after an exception occurs)
cause première
org.hibernate.AssertionFailure: null id in model.beans.Article entry (don't flush the Session after an exception occurs)
I am not using Maven.

Resources