Spring form:select not defaulting to saved object - java

I have a form that is representing a Role object. This role object can have one System object, which is selected via a drop-down list (form:select). It works perfectly except for one little snag: when editing the Role object the System object is not automatically selected on the list. From what I understand, it should be. Can anyone tell me why it isn't? Code is as follows:
Role class:
/**
* Represents a Role in the Database. Used for tracking purposes it allows us to
* find out what users and systems have certain roles. Role entity. #author
* MyEclipse Persistence Tools
*/
#Entity
#Table(name = "roles", catalog = "jess")
public class Role implements java.io.Serializable {
// Fields
private static final long serialVersionUID = -8599171489389401780L;
private Integer roleId;
#Valid
private System system;
...
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "SYSTEM_ID")
public System getSystem() {
return this.system;
}
public void setSystem(System system) {
this.system = system;
}
Controller:
#RequestMapping(value = "/" + MappingConstants.EDIT_ROLE + "/{id}",
method = RequestMethod.POST)
public ModelAndView getEditRoleForm(#PathVariable("id") Integer id)
{
Role r = new Role();
r.setRoleId(id);
Role role = roleService.searchAllRolesByID(r);
ModelAndView modelView = new ModelAndView(MappingConstants.ROLES_FOLDER + MappingConstants.EDIT_ROLE);
modelView.addObject(AttributeConstants.ROLE, role);
List<System> systems = systemService.searchAllSystems();
modelView.addObject(AttributeConstants.ALL_SYSTEMS, systems);
return modelView;
}
Property Editor:
public class SystemEditor extends PropertyEditorSupport
{
private final ISystemService systemService;
private static Logger logger = LogManager.getLogger(SystemEditor.class.getName());
public SystemEditor(ISystemService service)
{
super();
this.systemService = service;
}
/*
* (non-Javadoc)
* #see java.beans.PropertyEditorSupport#setAsText(java.lang.String)
*/
public void setAsText(String text) throws IllegalArgumentException
{
try
{
if(logger.isDebugEnabled())
logger.debug("System value coming in the editor as: {}", text);
System system = systemService.searchAllSystemsById(Integer.valueOf(text));
setValue(system);
}
catch (Exception e)
{
logger.error("There was an error attempting to process the System from the Editor.", e);
}
}
/*
* (non-Javadoc)
* #see java.beans.PropertyEditorSupport#getAsText()
*/
public String getAsText()
{
System system = (System) getValue();
return system.getSystemId().toString();
}
}
And jsp:
<form:form method="post" action="${contextPath}/jess/saveeditedrole" modelAttribute="role">
<h2>${role.name}</h2>
<br/><br/>
<form:errors path="system"/>
<form:label path="system">System:</form:label>
<form:select path="system">
<form:options items="${systems}" itemValue="systemId" itemLabel="fullName"/>
</form:select>

In your form:select you're using System class. Make sure this class has a proper .equals() and hashCode() methods, otherwise Spring doesn't know how to tell which System object is selected.

Related

How I can save information when I get exception in jpa

I've project with spring, spring-boot and JPA.
When a user tries to log in I want to register activity in a binnacle.
The authentication is with LDAP
I have a new class called LoginActivity and implement an interface with only one method to save activity with annotation #Component and my method where a want to save information when user put credentials wrong I have annotation
#Transactional(propagation = Propagation.REQUIRES_NEW)
And I have another method where I try to save information in my database
I debug my code and it looks good and the process finished well.
But when I saw my database I don't see anything
I use DTO objects between classes
My method authentication:
#Override
#Transactional
public Authentication authenticate(Authentication authentication) {
String name = authentication.getName();
String password = authentication.getCredentials().toString();
List<GrantedAuthority> authorities = (List<GrantedAuthority>) authentication.getAuthorities();
...
context = connect(user, password);//where authentication did
My DTO class, I use lombok
#Data
#Builder
public class LoginDTO {
private String user;
private String tracking;
private Map<String, Boolean> roles;
private String name;
private String lastName;
private boolean loginSuccess;
private String ipAddress;
}
I set every value in my class DTO
LoginDTO loginDTO = LoginDTO.builder()
.loginSuccess(true)
.tracking(tracking)
.lastName(lastName)
.name(name)
.roles(roles)
.user(user)
.ipAddress(httpServletRequest.getRemoteAddr())
.build();
loginActivity.saveLoginActivity(LoginDTO);
My interface
#FunctionalInterface
public interface LoginActivity {
public void saveLoginActivity(LoginDTO loginDTO);
}
My class than implement interface
#Component
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class LoginActivityImpl implements LoginActivity {
My entity
#Entity(name = "activity_desk_control")
#Setter
#Getter
public class ActivityDeskControlEntity {
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
#Basic(optional = false)
#Size(max = 255)
#Column(name = "id")
private String id;
#ManyToOne
#JoinColumn(name = "id_user_desk")
private DeskUserLogEntity idUserDesk;
#Column(name = "creation_date")
private Date creationDate;
#Column(name = "id_tracking")
private String idTracking;
#ManyToOne
#JoinColumn(name = "id_service_desk_control")
private ServiceDeskControlEntity idServiceDeskControl;
#Column(name = "params")
#Lob
private String params;
#Column(name = "url")
private String url;
#Column(name = "ip_address")
private String ipAddress;
#Column(name = "login_success")
private int loginSuccess;
#Column(name = "logout")
private int logout;
#Column(name = "logout_date")
private Date logoutDate;
}
My method where I save activity if authentication was well
public void saveMultipart(ActivityDeskControlEntity activityDeskControlEntity) {
this.activityDeskControlRepository.save(activityDeskControlEntity);
}
My method where I save activity if authentication was wrong
#Transactional(propagation = Propagation.REQUIRES_NEW)
public SimpleResponse saveMultipartLoginFail(ActivityDeskControlEntity activityDeskControlEntity) {
this.activityDeskControlRepository.save(activityDeskControlEntity);
}
Have you some idea how I can save information if I got an exception in JPA?
I look some links like this but not work.
My database is Oracle 19c
Update 1
The exception I get when I put credentials wrong is
javax.naming.AuthenticationException: [LDAP: error code 49 - Invalid Credentials]
In this scenario I want to save information the login fail.
Update 2
In the scenario that throws an exception is
context = connect(user, password);
For default LDAP throw an exception when user and password are wrong in consequence in this exception I want to save.
Update 3
I saw in documentation says:
Any RuntimeException or Error triggers rollback, and any checked
Exception does not.
When the user put credentials wrong throw an exception that extends RuntimeException
import org.springframework.security.core.AuthenticationException;
/**
* Thrown if an authentication request is rejected because the credentials are invalid.
* For this exception to be thrown, it means the account is neither locked nor disabled.
*
* #author Ben Alex
*/
public class BadCredentialsException extends AuthenticationException {
// ~ Constructors
// ===================================================================================================
/**
* Constructs a <code>BadCredentialsException</code> with the specified message.
*
* #param msg the detail message
*/
public BadCredentialsException(String msg) {
super(msg);
}
/**
* Constructs a <code>BadCredentialsException</code> with the specified message and
* root cause.
*
* #param msg the detail message
* #param t root cause
*/
public BadCredentialsException(String msg, Throwable t) {
super(msg, t);
}
}
/**
* Abstract superclass for all exceptions related to an {#link Authentication} object
* being invalid for whatever reason.
*
* #author Ben Alex
*/
public abstract class AuthenticationException extends RuntimeException {
// ~ Constructors
// ===================================================================================================
/**
* Constructs an {#code AuthenticationException} with the specified message and root
* cause.
*
* #param msg the detail message
* #param t the root cause
*/
public AuthenticationException(String msg, Throwable t) {
super(msg, t);
}
/**
* Constructs an {#code AuthenticationException} with the specified message and no
* root cause.
*
* #param msg the detailed message
*/
public AuthenticationException(String msg) {
super(msg);
}
}
I tried to change type of exception, but I couldn't, why? spring security to expected BadCredentialsException and not my own BadCredentialsException.
Are there any way to achieve that?
The simplest approach would be a try catch statement since the Stacktrace for the exception is missing in your question I ave to guess that your exception is thrown in line
context = connect(user, password);//where authentication did
A solution would then be
try {
context = connect(user, password);//where authentication did
} catch (AuthenticationException e) {
log.error("User could not autheticate");
someRepository.save(CustomErrorObject);
someOtherCustomSaveMethod();
throw e;
}
the error behavior is still the same since the exception is re thrown in the catch statement, but the save code before can be executed.

Spring boot API - How to ensure no concurrency issues

I'm still in the process of learning Java / spring and I think I'm getting better. Now at this point I'm able to build a rest api BUT I'm at a lost at how to ensure I've no concurrency issues . I've read many topics regarding making the API stateless or making my POJO's immutable but I'm sure if in my case below I need to. And if I did, I'm actually unsure how my code can function by making everything final in my POJO.
If someone could help me learn here I'd be VERY grateful. Thank you for your time
Below i have a POJO called User:
#Getter
#Setter
#Document(collection = "UserProfiles")
public class User {
#Id
#JsonIgnore
private String _id;
#JsonView({ProfileViews.Intro.class, ProfileViews.Full.class})
private String userId;
#JsonView({ProfileViews.Intro.class, ProfileViews.Full.class})
private String name;
#JsonView({ProfileViews.Intro.class, ProfileViews.Full.class})
private String displayName;
#DBRef
#JsonView({ProfileViews.Full.class})
private UserInterests personalInterests;
#DBRef
#JsonIgnore
private ProfileFollows profileFollowDetails;
}
#Getter
#Setter
#Document(collection = "ProfileFollows")
public class ProfileFollows {
#Id
//Id of The Mongo Document
private String id;
//The Id of the User Profile who owns the document
private String userId;
//A list containing the Ids of the Users who have followed the Profile belonging to userId
private List<String> profileFollowedByUserIds;
//A list containing the Ids of the Profiles the current user has followed
private List<String> profileFollowingByUserList;
}
And here is my Service layer where I create and update the user
#Service
public class UserService {
#Autowired
UserDal userDal;
public User createNewUserAccount(String userId, String userName) {
//check If userId already in DB
if (checkIfUserIdExits(userId)) {
throw new UserAlreadyExistsException("Cannot create User with Id { " + userId + " }, a user with this Id already " +
"exists");
}
//Create a Empty / Base New User Object
User newUser = new User();
UserInterests userInterests = new UserInterests();
userInterests.setUserId(userId);
userInterests.setPersonalInterestsExtras(null);
userInterests.setCreatedDate(Instant.now());
userInterests.setLastUpdatedAt(Instant.now());
userInterestsDAL.save(userInterests);
newUser.setPersonalInterests(userInterests);
ProfileFollows userProfileFollows = new ProfileFollows();
userProfileFollows.setUserId(userId);
userProfileFollows.setProfileFollowedByUserIds(new ArrayList<>());
userProfileFollows.setProfileFollowingByUserList(new ArrayList<>());
newUser.setProfileFollowDetails(profileFollowsDAL.save(userProfileFollows));
newUser.setUserId(userId);
newUser.setDisplayName(generateUserDisplayName(userName));
newUser.setCreatedDate(Instant.now());
newUser.setLastUpdatedAt(Instant.now());
//save the new User Profile to the DB
return userDal.save(newUser);
}
Here is my UserDAL:
public interface UserDal {
/**
* Method to check if a user exists with a given user Id
* #param Id -- Id of user to look up where id is a string
* #return
*/
Boolean existsById(String Id);
/**
* Method to save a user to the DB
* #param user -- User object to save to the DB
* #return
*/
User save(User user);
}
My User Repository / DALImpl:
#Repository
public class UserDALImpl implements UserDal {
private final MongoTemplate mongoTemplate;
#Autowired
public UserDALImpl(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
}
#Override
public User save(User user) {
return mongoTemplate.save(user);
}
And lastly my controller:
#RestController
#RequestMapping("/profile")
public class CreateProfileController {
#Autowired
public CreateProfileController() {
}
#Autowired
UserService userService;
#ApiOperation(value = "Allows for the creation of a user Profile")
#PostMapping("/create")
public User createUserProfile(#RequestParam(name = "userId") String userId,
#RequestParam(name = "displayName", required = true, defaultValue = "AnonymousDev") String displayName) {
if (userId.equals("")) throw new BadRequestException("UserId cannot be blank");
if (userService.checkIfUserIdExits(userId)) {
throw new UserAlreadyExistsException("Unable to create user with Id { " + userId + " }, the " +
"userId already exists");
}
return userService.createNewUserAccount(userId, displayName);
}
}

Why ResponseEntity calls hibernate while lazy loading active

Below is the DAO. I am getting the first UppeningUsers object. Note that here for this function I do not want to return peopleWhoBlockedMe set which is located inside the UppeningUsers..
But in different functions I would like to return that information. Note that Both of them are LAZY fetching. With evict I tried to detach the object but still it did not work.
First of all RESTcontroller is below. Then the DAO code is below. Then two entity descriptions are below.
Question is: I see that until
return new ResponseEntity(returned, HttpStatus.OK);
There is only one query which is the typical select. I do not want hibernate to go and take also UserBlock information of that specific UppeningUser. Because it is not needed for this service response. However even though it is lazy loading for some reason
return new ResponseEntity(returned, HttpStatus.OK);
calls the hibernate. I dont know why in restcontroller still it is connected to the database. I tried evict but didnt work.
The json response is
{"id":7,"peopleWhoBlockedMe":[{"blockedId":7}]}
But I do not want for this function to return this peopleWhoBlockedMe. It can be empty.
PLEASE NOTE that in other service for example I will explictly request this peopleWhoBlockedMe but just for this business logic I do not need this information. So what I can do to prevent this so whenever I actually want to call peopleWhoBlockedMe I can get it. Not automaticly.
#RestController
public class TempController {
#Autowired
UppeningUsersService uppeningUsersService;
#RequestMapping(value = "/testing", method = RequestMethod.GET)
public ResponseEntity<UppeningUsers> getPhotos() {
try {
UppeningUsers returned = uppeningUsersService.getUsersDetailsPartial();
return new ResponseEntity<UppeningUsers>(returned, HttpStatus.OK);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
This part is the DAO.
#Repository
public class UppeningUsersDAO {
#Autowired
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sf) {
this.sessionFactory = sf;
}
/**
* Get Existing user. Return error if there is not.
* #param incomingUser user who requested access.
* #return returns the guy information. All information.
*/
#Transactional
public UppeningUsers getUserDetails() throws Exception {
Session session = this.sessionFactory.getCurrentSession();
Query query = session.createQuery("from UppeningUsers ");
UppeningUsers returning = (UppeningUsers) query.list().get(0);
session.evict(returning);
return returning;
}
}
The main table is this one..
#Entity
#Table(name = "uppening_users")
#Proxy(lazy = true)
public class UppeningUsers {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private
int id;
#OneToMany(mappedBy = "blockedId",cascade =CascadeType.ALL, fetch = FetchType.LAZY)
private Set<UserBlocks> peopleWhoBlockedMe;
public UppeningUsers() {
super();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Set<UserBlocks> getPeopleWhoBlockedMe() {
return peopleWhoBlockedMe;
}
public void setPeopleWhoBlockedMe(Set<UserBlocks> peopleWhoBlockedMes) {
this.peopleWhoBlockedMe = peopleWhoBlockedMes;
}
}
Now here is the other table.
#Entity
#Table(name="user_blocks")
#Proxy(lazy = true)
public class UserBlocks {
#Id
#Column(name="id")
#GeneratedValue(strategy= GenerationType.IDENTITY)
int id;
#Column(name = "blocked_id",insertable = false,updatable = false)
private int blockedId;
public int getBlockedId() {
return blockedId;
}
public void setBlockedId(int blockedId) {
this.blockedId = blockedId;
}
}
UPDATE: 2 forgot to add the service
#Service("uppeningUserService")
public class UppeningUsersService {
#Autowired
UppeningUsersDAO uppeningUsersDAO;
public UppeningUsers getUsersDetailsPartial( ) throws Exception {
return uppeningUsersDAO.getUserDetails();
}
}
Jens is right about her sentence. The layer methodology and writing business objects fix the issue. Thank you.

Testing jpa entity classes - error Transaction is required

Based on an archetype i created a java ee app. There is an included arquillian test that runs fine. it just calls a method on a #Stateless bean that persists an pre-made entity.
now i added some entity with some relations and i wrote a test for them. But on peristing any entity i get
Transaction is required to perform this operation (either use a transaction or extended persistence context)
I think i need to mark the testmethod with #Transactional but it seems not to be in class path.
Manually invoking the transaction on injected EntityManager yields another error.
So how to correctly setup such tests and dependencies.
EDIT As Grzesiek D. suggested here are some details. this is the entity (the one thta links others):
#Entity
public class Booking implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* internal id.
*/
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", updatable = false, nullable = false)
private Long id;
/**
* Used for optimistic locking.
*/
#Version
#Column(name = "version")
private int version;
/**
* A booking must have a project related.
*/
#ManyToOne
#JoinColumn(name = "project_id")
#NotNull
private Project project;
/**
* A booking must have an owner.
*/
#ManyToOne
#JoinColumn(name = "user_id")
#NotNull
private User owner;
/**
* A booking always has a start time.
*/
#Column
#NotNull
private Timestamp start;
/**
* A booking always has an end time.
*/
#Column
#NotNull
private Timestamp end;
/**
*
* #return true if start is befor end. false otherwise (if equal or after end).
*/
#AssertTrue(message = "Start must before end.")
public final boolean isStartBeforeEnd() {
return start.compareTo(end) < 0;
}
/**
* #return the id
*/
public final Long getId() {
return id;
}
/**
* #param id
* the id to set
*/
public final void setId(final Long id) {
this.id = id;
}
/**
* #return the version
*/
public final int getVersion() {
return version;
}
/**
* #param version
* the version to set
*/
public final void setVersion(final int version) {
this.version = version;
}
/**
* #return the project
*/
public final Project getProject() {
return project;
}
/**
* #param project
* the project to set
*/
public final void setProject(final Project project) {
this.project = project;
}
/**
* #return the owner
*/
public final User getOwner() {
return owner;
}
/**
* #param owner
* the owner to set
*/
public final void setOwner(final User owner) {
this.owner = owner;
}
/**
* #return the start
*/
public final Timestamp getStart() {
return start;
}
/**
* #param start
* the start to set
*/
public final void setStart(final Timestamp start) {
this.start = start;
}
/**
* #return the end
*/
public final Timestamp getEnd() {
return end;
}
/**
* #param end
* the end to set
*/
public final void setEnd(final Timestamp end) {
this.end = end;
}
//hashCode, equals, toString omitted here
}
Here is the test:
#RunWith(Arquillian.class)
public class BookingTest {
#Deployment
public static Archive<?> createDeployment() {
return ArquillianContainer.addClasses(Resources.class, Booking.class, Project.class, User.class);
}
#Inject
private EntityManager em;
#Test
public void createBooking() {
Booking booking = new Booking();
booking.setStart(new Timestamp(0));
booking.setEnd(new Timestamp(2));
User user = new User();
user.setName("Klaus");
booking.setOwner(user);
Project project = new Project();
project.setName("theOne");
project.setDescription("blub");
booking.setProject(project);
em.persist(booking);
System.out.println("here");
}
}
And here the exception:
javax.persistence.TransactionRequiredException: JBAS011469: Transaction is required to perform this operation (either use a transaction or extended persistence context)
I know it will work if i create a #Stateless bean and encapsulate the persist there but i want a direct test of entity's validation and i need a playground to evolve the data model.
In order to have transaction support in Arquillian tests you will need to bring in extension which enables this feature. In your case jta dependency should do the job.
<dependency>
<groupId>org.jboss.arquillian.extension</groupId>
<artifactId>arquillian-transaction-jta</artifactId>
<scope>test</scope>
</dependency>
In addition, if you are using JBoss, you will need to provide its JNDI for UserTranscation, so put following section in your arquillian.xml:
<?xml version="1.0" ?>
<arquillian xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://jboss.org/schema/arquillian" xsi:schemaLocation="http://jboss.org/schema/arquillian
http://jboss.org/schema/arquillian/arquillian_1_0.xsd">
<extension qualifier="transaction">
<property name="manager">java:jboss/UserTransaction</property>
</extension>
</arquillian>
This way you can use #Transactional which comes from this extension's API.

How to save specific properties of a JPA entity model attribute from JSP page

We are using JPA entity beans as our model for Spring MVC controller on a jsp page. One of our jsp pages is a partial view of this entity which does not show all properties. Whenever we try to update our entity using the service layer from the controller only the properties used on the jsp form are persisted and all others are nulled out. What is the correct way to handle this situation? We do not want to have to specify hidden fields on the form.
So in this case when the controller calls the service.update(client) method the name field will be null because it does not exist in the form.jsp.
form.jsp
<form:form modelAttribute="client" method="get" action="${action}">
<table width="100%">
<tr>
<td>
<table>
<tr>
<td valign="top"><spring:message code="label.tradeOrderManagementSystem"/>:</td>
<td>
<form:select path="tradeOrderManagementSystems" >
<form:options items="${tradeOrderManagementSystemList}" itemValue="id" itemLabel="name" />
</form:select>
<span><spring:message code="add"/></span>
</td>
<td>
<form:errors path="tradeOrderManagementSystems" cssClass="errors" />
</td>
</tr>
<tr><td></td><td> </td></tr>
</table>
</td>
</tr>
</table>
<input type="hidden" name="submitted" value="true">
controller
#RequestMapping("/{id}/edit")
public ModelAndView edit(HttpServletRequest request,
HttpServletResponse response,
#ModelAttribute("client") Client client,
BindingResult result,
#PathVariable("id") int id,
Model model) {
ControllerContext ctx = new ControllerContext(request, response);
init(ctx);
setAdvancedSearchAvailable(ctx, true);
buildShowAndEditVerticalMenu(ctx, id, false);
if (id == 0) {
result.addError(new ObjectError("client", getMessage("error.idNeeded")));
return getModelAndView(ctx, "itEfficiencies/form");
} else {
if (!isSubmission(ctx)) {
client = clientService.find(id);
model.addAttribute("client", client);
fillClientForm(model);
return getModelAndView(ctx, "itEfficiencies/form");
} else {
//clientValidator.validate(client, result);
if (result.hasErrors()) {
fillClientForm(model);
return getModelAndView(ctx, "itEfficiencies/form");
} else {
try {
//checkClientProperties(client);
client.setId(id);
client = clientService.update(client); //method updates only form fields and nulls out all others
} catch (Exception e) {
e.printStackTrace();
result.addError(new ObjectError("client", getMessage("error.save")));
fillClientForm(model);
return getModelAndView(ctx, "itEfficiencies/form");
}
return getModelAndView(ctx, "/staffingByClient/" + client.getId() + "/show", true);
}
}
}
}
Client.java
#Entity
public class Client extends AbstractEntity<Integer> {
private static final long serialVersionUID = 1L;
public static final String FIND_BY_NAME = "Client.FIND_BY_NAME";
public static final String COUNT_BY_NAME = "Client.COUNT_BY_NAME";
#Basic(optional = false)
#Column(nullable = false, length = 125)
private String name;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(inverseJoinColumns = {
#JoinColumn(name = "trade_order_management_system_id")}, uniqueConstraints =
#UniqueConstraint(name = "UK_client_trade_order_mgmt_client_id_trade_order_mgmt_id",
columnNames = {"client_id", "trade_order_management_system_id"}))
#ForeignKey(name = "FK_client_trade_order_management_systems_client_id",
inverseName = "FK_client_trade_order_mgmt_sys_trade_order_management_system_id")
private List<TradeOrderManagementSystem> tradeOrderManagementSystems;
public Client() {
}
public Client(Integer id) {
this.id = id;
}
public Client(Integer id, String name) {
this.id = id;
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<TradeOrderManagementSystem> getTradeOrderManagementSystems() {
return tradeOrderManagementSystems;
}
public void setTradeOrderManagementSystems(List<TradeOrderManagementSystem> tradeOrderManagementSystems) {
this.tradeOrderManagementSystems = tradeOrderManagementSystems;
}
#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 Client)) {
return false;
}
Client other = (Client) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
}
service methods
public abstract class CrudService<T, ID extends Serializable> extends DAOImpl<T, ID> {
/**
* Updates an entity from an existing entity.
*
* #since 0.0.1
*
* #param entity
* #return the managed instance of the updated entity
*/
#Override
#Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
public T update(T entity, ID id) {
return super.update(assignDefaultValues(entity), id);
}
}
public abstract class DAOImpl<T, ID extends Serializable> implements DAO<T, ID> {
private Class<T> persistentClass;
#PersistenceContext(unitName = "krfsPersistenceUnit")
protected EntityManager entityManager;
/**
* Instantiates an instance of this class and sets the <code>persistentClass</code>
* based on the identifier type
*
* #since 0.0.1
*/
public DAOImpl() {
this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
/**
* #since 0.0.1
*
* #return the type to be persisted
*/
#Override
public Class<T> getPersistentClass() {
return persistentClass;
}
/**
* Updates an entity from an existing entity.
*
* #since 0.0.1
*
* #param entity
* #param id the identifier of the entity
*
* #return the managed instance of the updated entity
*/
#Override
public T update(T entity, ID id) {
//Find a managed instance of the entity first and copy the properties
//to the passed in entity before merging. This ensures that entityManager
//will not create a new entity with merge.
Object ref = this.entityManager.getReference(persistentClass, id);
if (ref != null) {
BeanUtils.copyProperties(entity, ref);
}
return (T) this.entityManager.merge(ref);
}
}
You aren't really giving enough details (specifically, the code showing how you save the values from the form would help) but I suspect that you're merging a detached entity with null attributes. And because of the way merge works (it copies the state of the detached entity onto a entity with the same database identifier loaded in the persistence context), you get NULLs.
You need to either:
somehow keep the detached entity, copy the values form the form into it, and then merge it ~or~
implement a "manual merge" i.e. load the entity to update using using its id, copy the new values from the model and let JPA update it.
If I missed the point, please provide more details to understand the problem.
Update: I don't understand your code. You're copying properties from ref to entity (the detached client coming from the view), then merging ref... No, I don't get it.

Categories

Resources