i can't send modelAttribute that contains a mapped object from another class - spring

I have a problem in a matter concerning a mapped object.
here are the entities used:
#Entity
#Table(name = "skill")
public class Skill {
.
.
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "collab_id")
private Collaborateur collaborateur;
........................
#Entity
#Table(name = "collaborateur")
public class Collaborateur {
.
.
#OneToOne(fetch = FetchType.LAZY, mappedBy = "collaborateur")
private Skill skill;
My jsp file :
<form:form action="/app/skill" method="post" modelAttribute="skill"
id="myForm">
<div>
<fieldset>
<legend>Recherche de skill par critere :</legend>
.
.
.
<form:select path="collaborateur" id="input" >
<form:option value="" label="--Collaborateur--"></form:option>
<form:options path="collaborateur" items="${collaborateurs}" itemLabel="firstname" itemValue="id"/>
</form:select>
<input type="submit" value="Search" name="Search"
class="searchButton" onclick="pagination('${1}', '${size}')" />
</fieldset>
When i try to search for a "collaborateur" in a "skill" list, using Example from spring data,i get the this error.
org.springframework.dao.InvalidDataAccessApiUsageException: Path
'collaborateur.skill.collaborateur' from root Skill must not span a cyclic
property reference!
[{ com.app.entities.Skill#a648b00 }] -collaborateur-> [{
com.app.entities.Collaborateur#2b }] -skill-> [{
com.app.entities.Skill#33a1c699 }] -collaborateur-> [{
com.app.entities.Collaborateur#2b }]
What causing this error ?

Related

how to pass value in thymleaf, checking entity for betting service

creating simple match betting service. I have a problem in thymeleaf with passing the value of the match on which the user is currently betting. I want to pass the ID of the match I am betting on to the bet table. I'm not entirely sure about the entities I have whether they are designed correctly. Currently to the bet table passes me the team that the user is betting on by entering the name on input, I want to pass the match ID as well but without entering.
Bet entity
#Entity
#AllArgsConstructor
#NoArgsConstructor
#Setter
#Getter
#Builder
public class Bet {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#ManyToOne
#JoinColumn(name = "employee_id")
private Employee employee;
#ManyToOne(cascade = CascadeType.REMOVE)
#JoinColumn(name = "match_id")
private Match match;
#Column(name = "team_bet")
private String teamBet;
private String result;
}
Match entity
#Entity
#AllArgsConstructor
#NoArgsConstructor
#Setter
#Getter
#Builder
public class Match {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name = "first_team_name")
private String firstTeamName;
#Column(name = "second_team_name")
private String secondTeamName;
#DateTimeFormat(pattern ="yyyy-MM-dd")
private Date dateOut;
#OneToMany(mappedBy = "match", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<Bet> bet = new HashSet<>();
private String timeOut;
}
Controllers
#GetMapping("/matches/bet/{id}")
public String createBet(Model model, #PathVariable(name = "id") int matchId) throws MatchNotFoundExceptions {
Match match = matchService.getMatch(matchId);
Bet bet = new Bet();
model.addAttribute("match", match);
model.addAttribute("bet", bet);
return "bet_form";
}
#PostMapping("/bet/save")
public String saveBet(Bet bet, RedirectAttributes redirectAttributes) {
betService.createBet(bet);
redirectAttributes.addFlashAttribute("message", "The bet has been created successfully!");
return "redirect:/bets";
}
bet_form.html
<form th:action="#{/bet/save}" method="post"
style="max-width: 700px; margin: 0 auto" th:object="${bet}">
<input type="hidden" th:field="*{id}"/>
<input type="hidden">
<form th:object="${match}">
<!--send to bet entity-->
<td th:text="${id}"></td>
</form>
<div style="text-align: center" class="m-3">
<b>Match Start: </b>
<td th:text="${#dates.format(match.dateOut, 'yyyy-MM-dd')}"></td>
<td th:text="${match.timeOut}"></td>
<div style="text-align: center" class="m-3">
<a th:text="${match.firstTeamName}"></a>
<b>VS</b>
<a th:text="${match.secondTeamName}"></a>
<div class="m-4">
<b>Team Name:</b>
<input type="text" class="form-control"
th:field="*{teamBet}" required minlength="3" maxlength="24"/>
</div>
</div>
</div>
<div class="text-center">
<div class="m-3">
<input type="submit" value="accept" class="btn btn-primary"/>
<input type="submit" value="cancel" class="btn btn-warning"
onclick="location.href='/matches';"/>
</div>
</div>
</form>

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)

hibernate validation not working while one-to-one mapping in between two entities

During form submission, if there is any validation error then form shows the errors messages under the fields. But the actual problem is in another place. I have two entities User and UserDetails. These entities are mapped with each other by bidirectional one-to-one mapping. Validation is working only with the User entity fields but not with the UserDetails entity.
Spring - 5.0.2`
Hibernate - 5.2.10
User.java
#Entity
#Table(name="users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#NotEmpty(message="{common.error.msg}")
private String first_name;
#NotEmpty(message="{common.error.msg}")
private String last_name;
#NotEmpty(message="{common.error.msg}")
private String status;
#OneToOne(cascade = CascadeType.ALL, mappedBy = "user", fetch = FetchType.LAZY)
private UserDetails userDetails;
//Getter and setter methods
}
UserDetails.java
#Entity
#Table(name="user_details")
public class UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int user_id;
#NotEmpty(message="{common.error.msg}")
private String address;
#NotEmpty(message="{common.error.msg}")
private String mobile;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id")
private User user;
//Getter and setter methods
}
Get and Post methods in the controller class
#GetMapping(value="/create")
public String loadUserForm(Model model) {
model.addAttribute("command", new User());
return "backend/oms/user/form"; //JSP
}
#PostMapping(value="/create")
public String Save(#Valid #ModelAttribute("command") User user, BindingResult br, Model model, HttpSession session, RedirectAttributes ra) {
if(br.hasErrors()) {
return "backend/oms/user/form"; //JSP
} else {
try {
int id = userService.save(user);
if(id > 0) {
ra.addFlashAttribute("flash_msg", "ok|User added!");
return "redirect:/oms/user/edit/"+id;
} else {
return "backend/oms/user/create"; //JSP
}
} catch (ConstraintViolationException ex) {
model.addAttribute("err", "Something wrong! Please try again.");
return "backend/oms/user/form"; //JSP
}
}
}
messages.properties
common.error.msg=This field is required!
form.jsp
<form:form action="/oms/user/create" method="post" modelAttribute="command">
<label>First Name</label>
<form:input path="first_name" class="form-control" placeholder="First Name" value="" />
<form:errors cssClass="error" path="first_name" />
<label>Last Name</label>
<form:input path="last_name" class="form-control" placeholder="Last Name" value="" />
<form:errors cssClass="error" path="last_name" />
<label>Mobile</label>
<form:input path="userDetails.mobile" class="form-control" placeholder="Mobile" value="" />
<form:errors cssClass="error" path="userDetails.mobile" />
<label>Address</label>
<form:textarea path="UserDetails.address" class="form-control" placeholder="Address" value="" />
<form:errors cssClass="error" path="userDetails.address" />
<label>Status</label>
<form:select class="form-control" path="status">
<option value="">Choose...</option>
<option value="E">Enable</option>
<option value="D">Disable</option>
</form:select>
<form:errors path="status" cssClass="error"/>
<input type="submit" class="btn btn-primary" value="Save" />
</form>
Please see the screenshot
As you can see the image only fields from the User entity is validating but fields those are from the UserDetails are not validating. Please help.
It is solved now. #Valid annotation solved my problem. I need to put #Valid annotation before the entity variable declaration like below --
#OneToMany(mappedBy="majorHead", cascade = CascadeType.ALL)
#Valid
private List<MinorHead> minorHead = new ArrayList<MinorHead>();

Creating HTML form with Spring+Hibernate

I have 3 classes:
First class, is an entity, that stores String variable:
#Entity
#Table(name = "mods_langs_texts", catalog = "artfunpw")
#Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
public class ModsLangsTexts implements java.io.Serializable {
#Column(name = "Title", nullable = false, length = 300)
public String getTitle() {
return this.title;
}
Second entity is for relations:
#Entity
#Table(name = "mods_langs_texts_relations", catalog = "artfunpw")
#Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
public class ModsLangsTextsRelations implements java.io.Serializable {
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "textId", nullable = false)
public ModsLangsTexts getModsLangsTexts() {
return this.modLangsTexts;
}
And the third entity is the main class:
#Entity
#Table(name = "mods", catalog = "artfunpw")
#Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
public class Mod implements java.io.Serializable {
#OneToMany(fetch = FetchType.EAGER, mappedBy = "mod")
#Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
public Set<ModsLangsTextsRelations> getModsLangsTextsRelationses() {
return this.modsLangsTextsRelationses;
}
I am trying to create HTML form with the code:
m.addAttribute("formClass", mod);
And HTML code:
<p th:text="${formClass.modsLangsTextsRelationses.toArray()[0].getModsLangsTexts().title}" />
<form action="" th:object='${formClass}' method="POST">
<input type="hidden" th:field='*{id}' />
Title: <input type="text" th:field='${formClass.modsLangsTextsRelationses.toArray()[0].getModsLangsTexts().title}' />
<br />
But it fails with error:
2017-10-13 14:33:56.661 ERROR 4744 --- [nio-8080-exec-9] org.thymeleaf.TemplateEngine : [THYMELEAF][http-nio-8080-exec-9] Exception processing template "mods/editPages/editModPage": Error during execution of processor 'org.thymeleaf.spring4.processor.attr.SpringInputGeneralFieldAttrProcessor' (mods/editPages/editModPage:57)
Where line 57 is the line with code:
Title: <input type="text" th:field='${formClass.modsLangsTextsRelationses.toArray()[0].getModsLangsTexts().title}' />
In the same time, code
<p th:text="${formClass.modsLangsTextsRelationses.toArray()[0].getModsLangsTexts().title}" />
works fine.
How can I access inner objects from HTML form code with Spring+Hibernate+Thymeleaf?
Have a look at the thymeleaf tutorial :
The th:field is a field reference to a command object you declare on the form tag thanks to the th:object attribute
From the tutorial :
<form action="#" th:action="#{/seedstartermng}" th:object="${seedStarter}" method="post">
<input type="text" th:field="*{datePlanted}" />
</form>
Adapted to your case it would be something like :
<form action="#" th:action="#{???}" th:object="${formClass.modsLangsTextsRelationses.toArray()[0].getModsLangsTexts()}" method="post">
<input type="text" th:field="*{title}" />
</form>
I have a doubt it will work this way. Have a look at section 7.6 : dynamic fields

JasperException: java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'user' available as request attribute

I have two Data Model : User and Car, User can have many cars , so this is the User Class :
#Entity
#Table(name="APP_USER")
public class User implements Serializable{
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
......
#OneToMany(mappedBy="user",cascade=CascadeType.ALL)
private Set<Car> cars = new HashSet<Car>();
Car.java :
#Entity
public class Car implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id ;
.....
#ManyToOne(optional=false)
#JoinColumn(name="user_fk")
private User user;
In the carController , I have the method to add a new Car for one user :
#Controller
#RequestMapping("/cars")
public class CarController {
#Autowired
CarService carService;
#Autowired
UserService userService;
#RequestMapping(value={"/list"},method=RequestMethod.GET)
public String listCars(ModelMap model){
List<Car> cars = carService.allCars();
model.addAttribute("cars", cars);
return "car"; }
#ModelAttribute("utilisateurs")
public List<User> allUsers(){
List<User> utilisateurs = userService.findAllUsers();
return utilisateurs;
}
#RequestMapping(value={"/newCar"},method=RequestMethod.GET)
public String newCar(ModelMap model){
Car car = new Car();
model.addAttribute("car",car);
return "carRegistration";
}
#RequestMapping(value={"newCar"},method=RequestMethod.POST)
public String newCar(#Valid Car car, BindingResult result,ModelMap model){
if (result.hasErrors()) {
return "registration";
}
carService.save(car);
model.addAttribute("car",car);
return "redirect:/cars/list";
}
Finally , in the view , the form is :
<form:form method="POST" modelAttribute="car"
class="form-horizontal">
<form:input type="hidden" path="id" id="id" />
<div class="control-group">
<label class="control-label">Libelle</label>
<div class="controls">
<form:input type="text" path="libelle" id="libelle" style="height:4%" />
</div>
</div>
<div class="control-group">
<label class="control-label">Registration</label>
<div class="controls">
<form:input type="text" path="registration" id="email" />
</div>
</div>
<div class="control-group">
<label class="control-label">Utilisateur</label>
<div class="controls">
<form:select path="user" items="${utilisateurs}" itemValue="id" itemLabel="lastName" style="margin-left: 4%;"></form:select>
</div>
</div>
<div class="form-actions">
<input type="submit" value="Validate" class="btn btn-success" />
</div>
</form:form>
I can get the view , but when I click on button submit , I get this error :
Neither BindingResult nor plain target object for bean name 'user' available as request attribute.
I think there is a problem with the select item of users !!
Have you provided any Spring converter or formatter for User ?
applicationContext.xml:
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="my.project.StringToUser"/>
<bean class="my.project.StringToRole"/>
</list>
</property>
</bean>
<mvc:annotation-driven conversion-service="conversionService" />
It will convert User id to User object.
my.project.StringToUser:
import org.springframework.core.convert.converter.Converter;
public class StringToUser implements Converter<String, JUser> {
#Autowired
private UserService userService;
#Override
public JUser convert(String source) {
long id = Long.valueOf(source);
return userService.get(id);
}
}
the error :
WARNING: Failed to bind request element: org.springframework.beans.TypeMismatchException:
Failed to convert value of type [com.websystique.springmvc.model.User] to required type [com.websystique.springmvc.model.User];
nested exception is org.springframework.core.convert.ConversionFailedException:
Failed to convert from type [com.websystique.springmvc.model.User] to
type [#org.springframework.web.bind.annotation.ModelAttribute #javax.validation.Valid com.websystique.springmvc.model.User]
for value 'User [id=null, ssoId=alaa, password=alaa1991, firstName=, lastName=, email=, userProfiles=null, accounts=null, userDocuments=[], cars=[], documents=[]]';
nested exception is java.lang.ClassCastException:
com.websystique.springmvc.model.User cannot be cast to java.lang.String

Resources