I have a Website model, that has a #Required User owner property. This property gets filled inside the controller method. However, validation is checked upon entering the controller method, so it considers the object invalid (because at the time, it is).
Should Play! validation be used for this purpose?
Should I just drop the #Valid annotation and check manually using validation.required(website)?
Update - using validation.required(website) only validates that the website is not null, but it does not run validate any of the annotations on the website. If I'm not using the #Valid parameter annotation, does this mean I can't use annotation-based validations on the model itself? What's a programmer to do?
Update2 - it seems I should be calling validation.valid(website) instead of validation.required(website). I also added a #Required annotation to the add() method parameter (instead of #Valid). Is this the way it should be done?
#Entity
public class Website extends PortalModel {
#Required
public String url;
#Required
#ManyToOne
public User owner;
}
public class Sites extends UserAwareControllerBase {
public static void added(#Valid Website website) {
website.owner = getUser(); // from base class
if (Validation.hasErrors()) {
Validation.keep();
params.flash();
add();
}
websiteRepo.save(website);
edit(website.id);
}
}
I'm not sure if there's a point to declare User as #Required if your app's users have no influence on it. Well, it's a safety net for your own code.
But since the user is not in the parameters when you submit the website form, you have to validate manually:
website.owner = getUser();
validation.valid(website);
...
Related
I'm in the middle of migrating a project from:
Spring 4.2.1 -> 5.0.0
Spring Data Gosling -> Kay
Hibernate 4.3.8 -> 5.8.0
And I'm running getting "org.hibernate.LazyInitializationException: could not initialize proxy - no Session" when accessing an object coming from my database in a controller method.
Here's a stripped down version of my code:
// CustomUser.java
#Entity
#Access(AccessType.FIELD)
#Table(name = "users")
public class CustomUser implements Serializable {
...
#Id
#GeneratedValue//details omitted
#GenericGenerator//details omitted
#Column(name = "id", insertable = true, updatable = true, unique = true, nullable = false)
private Long id;
#Column(name = "name")
private String name;
public String getName() { return name; }
}
// UserController.java
#RequestMapping(value = "/user/{userId}/", method = RequestMethod.GET)
public String showUser(#PathVariable("userId") CustomUser user) {
System.out.println("user name is [" + user.getName() + "]");
return "someTemplate";
}
// UserService.java
#Service
public class UserServiceImpl implements UserService {
#Autowired UserRepository userRepository;
#Override
public User findUserById(Long userId) {
return userRepository.getOne(userId);
}
}
// UserRepository.java
public interface UserRepository extends JpaRepository<CustomUser, Long> { }
// UserConverter.java
#Component
public class UserConverter implements Converter<String, CustomUser> {
#Autowired UserService userService;
#Override
public CustomUser convert(String userId) {
CustomUser user = userService.findUserById(SomeUtilClass.parseLong(userId));
return user;
}
}
There's also a #Configuration WebMvcConfigurerAdapter class that autowires a UserConverter instance and adds it to a FormatterRegistry.
Prior to starting this upgrade, I could hit:
http://server:port/user/123/
and Spring would take the "123" string, the UserConverter::convert method would fire and hit the Postgres database to look up a user with that id, and I'd get back a CustomUser object in my controller's "showUser" method.
But, now I am getting the org.hibernate.LazyInitializationException. This is occurring when I attempt to print out the user's name in the "showUser" method - or even just "println(user)" without accessing a field.
Most of the info I've been able to turn up from searching suggests that this exception comes from having an object having a lazily loaded collection of sub objects (like if my CustomUser had a collection of Permission objects or something that mapped to a different database table). But in this case I'm not even doing that, this is just a field on the object.
My best guess at the moment is this is due to some kind of hibernate session being terminated after the Converter does its work, so then back in the controller I don't have a valid session. (although again, I don't know why the CustomUser object is coming back unusable, I'm not attempting to fetch a subcollection).
I have added the Hibernate annotation "#Proxy(lazy = false)" to my CustomUser.java and if I do that the problem goes away. But, I'm not sure this is a good solution - for performance reasons, I really don't think I want to go down the road of eagerly fetching EVERYTHING.
I've also tried annotating various things (the service method, the controller method, etc.) with #Transactional; I haven't gotten that to work but I am still reasonably new to Spring and I may be trying that in the wrong place or misunderstanding what that should do.
Is there a better way to handle this than just "#Proxy(lazy = false)" on all of my Entity classes?
The immediate problem comes from the use of userRepository.getOne(userId). It is implemented in the SimpleJpaRepository using EntityManager.getReference. This method returns just a Proxy, which only contains its id. And only when a property gets accessed those get lazy loaded. This includes simple properties like name in your case.
The immediate fix is to use findOne which should load all the eager properties of your entity which should include simple properties, so the exception goes away.
Note that this will slightly change the behavior of your converter. The current version will not fail when the id is not existent in the database because it never checks. The new one will obtain an empty Optional and you'll have to convert it to null or throw an exception.
But there is (or might be) a bigger problem hiding: The entity is still detached because in absence of an explicit transaction demarcation the transactions only span single repository calls. So if you later want to access lazy loaded properties, you might get the same problem again. I see various options to consider:
Leave it as it is, being aware that you must not access lazy loaded properties.
Make sure a transaction is started before the converters get invoked.
Mark your controllers with #Transactional and loading the user (again) in the controller.
I'm looking to implement bean validation with groups based on parameter. The idea is to have methods with signature like:
#POST
#Path("/id-{id}")
public SomeDTO updateProducer(#PathParam("id") String id, #MatrixParam("update") Class<ConvertGroupTarget> update, #Valid SomeDTO data);
This would serve as an equivalent of explicit ConvertGroup declaration, such as:
#POST
#Path("/id-{id}")
public SomeDTO updateProducer(#PathParam("id") String id, #Valid #ConvertGroup(from=Default.class, to=/*some class that implements ConvertGroupTarget*/) SomeDTO data);
Is this even possible at all? We're using Jersey with hibernate-validator.
EDIT: the purpose of this all. Say I want to validate beans based on some validation group for specific purposes. For example, some bean can have different rules that apply to creating and updating it. So the bean declaration looks like this:
class SomeDTO {
#NotNull(groups = {Create.class, Update.class})
private String id;
#NotNull(groups = {Create.class, Update.class})
private String name;
#NotNull(groups = Update.class)
private String something;
//getters, setters etc.
}
The classes Create and Update are just some marker classes/interfaces to provide typed declaration of the groups.
Now, say the API user is creating an entity and he does
POST /id-X123/;update=create. Here I just want to validate the ID and the name, but don't really care about the something property of the bean. But when API user wants to update the bean, the API should require that he specifies even the something property. This is normally done by converting the validation group - #ConvertGroup(from = Default.class, to = Create.class) for creating and #CovertGroup(from = Default.class, to = Update.class) for updating. However, I'm looking to skip the explicit declaration of a ConvertGroup annotation and do this programatically based on parameter.
ConvertGroup defines static group conversions so you won't have the ability to parameterize them. You define them once and for all.
I think what you want to do is to call the Validator with a group. I don't use Jersey so I don't know if they have a hook for it but what you should look for is this:
Set<ConstraintViolation<SomeDTO>> violations =
validator.validate(someDTO); // validate the default group
Set<ConstraintViolation<SomeDTO>> violations =
validator.validate(someDTO, Update.class); // validate the Update group
How can I prevent user from entering HTML or Java script tags in input type in Spring MVC? There should be a server side validation. I am working on a project with thousands of JSPs and controllers. How can I do this?
If you want a server side solution, you could implement a redirect filter that eliminates everything that contains javascript tags and javascript code. Another way is to check the input values in the controller's method that is associated with it.
You probably have to redesign a few things. First, you should always validate the user input twice: once client-side, once server-side.
Thus, you will need to validate the user input in your JavaScript code (using a Regexp probably), and to validate it again in your Java code.
If your application follow the usual design patterns, your controller receives a DTO as a parameter to the entry-point. There you can use the #Valid annotation and add all the necessary rules on the fields of your DTO (using javax.validation annotations).
While there may be many possible answers, one of them is using JSR 303 validator framework.
You can include hibernate validator to use JSR 303 framework.
First step is applying different type of constraint on your class. For example
example taken from : Hibernate Validator - Reference - 1.2. Applying constraints
package org.hibernate.validator.referenceguide.chapter01;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
public class Car {
#NotNull //manufacturer must never be null
private String manufacturer;
#NotNull
#Size(min = 2, max = 14) //licensePlate must never be null and must be between 2 and 14 characters long
private String licensePlate;
#Min(2)
private int seatCount; //seatCount must be at least 2
//getters and setters ...
}
Now in your controller, use #Valid annotation to validate your car object and also pass a BindingResult parameter, that will validate whether this object is valid or not
#Controller
#RequestMapping("/car")
public class CarController {
#RequestMapping(value = "/newcar", method = RequestMethod.POST)
public String addCustomer(#Valid Car car, BindingResult result) {
if (result.hasErrors()) {
//car data is not valid, enter data again
return "AddNewCar.jsp";
} else {
//save car logic here
return "CarSavedSuccessfully.jsp";
}
}
}
I have a simple #Controller class that renders a page after user has logged in:
#Controller
#SessionAttributes("user")
public class DashBoardController {
#RequestMapping(value="/user/dashBoard", method=RequestMethod.GET)
public String showDashBoardPage(#ModelAttribute("user") User user, Model model) {
//do some work here....
return "dashBoard";
}
}
as you see, user attribute is already present in session and by using #ModelAttribute annotation I only want to pull it from there, nothing else. But if you add any parameter to request, then spring tries to bind this parameter to existing user object, which is not what I want, how to forbid this behavior?
To be more specific, here's the User class:
public class User {
private String name;
private String password;
private Language language;
//public getters and setters here...
}
If I want to change language of my dashBoard page, I request this page with addition of ?language=en parameter and in this case Spring tries to change language field of user model attribute, which of course fails with type mismatch exception.
Of course I can walk around by changing parameter name to something that doesn't match any of User fields, but that seems like a fragile solution.
Is there any way to control this data binding behavior?
I use Spring 4.1.3
There is an attribute of #ModelAttribute called binding which you can set to false to disable binding of request parameters. Usage: #ModelAttribute(binding=false) before method parameter.
Reference: click
It's about passing interface of DTO to DAO.
For example I have following code
public interface User {
String getName();
}
public class SimpleUser implements User {
protected String name;
public SimpleUser(String name) {
this.name = name;
}
#Override
public String getName() {
return name;
}
}
// Mapped by Hibernate
public class PersistentUser extends SimpleUser {
private Long id;
// Constructor
// Getters for id and name
// Setters for id and name
}
I'm using generic DAO. Is it ok if I create DAO with using interface User instead PersistentUser?
User user = new PersistentUser(name);
UserDao.create(user);
I read a lot of topics on stack but not figured out is this approach ok or no. Please help me. Maybe this is stupid and I can achive only problems.
About separating beans.
I did this because some classes I want to share via API module, that can be used outside to create entities and pass them to my application. Because they uses interface I developed so I can pass them to my DAO for persisting.
Generally, I would say it is ok, but there are a few hidden problems. A developer could cast the object down or access some state via a toString method that shouldn't be accessible. If you don't be careful, it could happen that state is serialized as JSON/XML in webservices that shouldn't be serialized. The list goes on.
I created Blaze-Persistence Entity Views for exactly that use case. You essentially define DTOs for JPA entities as interfaces and apply them on a query. It supports mapping nested DTOs, collection etc., essentially everything you'd expect and on top of that, it will improve your query performance as it will generate queries fetching just the data that you actually require for the DTOs.
The entity views for your example could look like this
#EntityView(PersistentUser.class)
interface User {
String getName();
}
Querying could look like this
List<User> dtos = entityViewManager.applySetting(
EntityViewSetting.create(User.class),
criteriaBuilderFactory.create(em, PersistentUser.class)
).getResultList();