I have an object in API jar, that I cannot change:
public class User {
#NotNull
private String name;
#NotNull
private String password;
}
In my code I need to use this object and to validate data inside, but, for example, I would like to let the password be empty. I cannot remove #NotNull from the class (and I cannot define groups for given constraint). How can I influence the validation without redefinig it from scratch?
One possible solution is to override the constraint definition of the specific class using either the constraint-mapping xml file or the Hibernate Validator specific API.
As described in the documentation, you can overide specific annotations (like the password field annotation) and leave the others untouched.
<constraint-mappings ...>
<bean class="User" ignore-annotations="false">
<field name="password" ignore-annotations="true">
... new annotations
</field>
</bean>
</constraint-mappings>
further reading:
http://docs.jboss.org/hibernate/validator/5.1/reference/en-US/html/chapter-xml-configuration.html#section-mapping-xml-constraints
http://docs.jboss.org/hibernate/validator/5.1/reference/en-US/html/validator-specifics.html#section-programmatic-api
Related
everyone.
So, I have a SpringBoot application with a controller that has several methods, taking the following POJO as a parameter:
package com.example.dto;
import lombok.Data;
#Data
public class MyEntity {
#NotNull
private String fieldA;
private String fieldB;
}
For one of the controller endpoints I would like to apply additional validation logic, so in the validation.xml I add the following:
<constraint-mappings>
<bean class="com.example.controller.SampleController" ignore-annotations="false">
<method name="doFoo">
<parameter type="com.example.dto.MyEntity">
<valid />
<constraint annotation="com.example.validation.ValidEntity" />
</parameter>
</method>
</bean>
</constraint-mappings>
com.example.validation.ValidEntity is the constraint annotation I would like to apply.
My problem is that this additional constraint is only invoked if #NotNull checks defined in MyEntity have passed successfully. If fieldA is null, ValidEntity constraint is ignored, and the client receives an imcomplete validation result. What am I missing?
I'm not entirely sure about this because I've never worked with the validation.xml file.
However, I would say that Spring is first creating the object and then applying the validations. The #NotNull validation is performed in the creation of the instance. This means that if that validation fails the construction will throw an exception and Spring won't even try to check your constraint (which makes sense in my opinion).
I think you can "fix" it by creating an annotation with your constraint and using it in your class. If I'm right, both annotations will be checked and the thrown exception will contain all errors.
It's just a guess. Let me know if it works.
I don't know if there is an easy way to configure the validator to aggregate constraint violations from both annotation and XML configurations when first or both fails.
As demonstrated by your code Hibernate Validator can work with mixed annotation and XML configurations, but the lack of documentation for that specific case is a hint that it is at least not recommended.
When XML configuration file is used, it takes precedence over annotations by default. ignore-annotations is used to overcome this (text highlight is mine):
Setting ignore-annotations to true means that constraint
annotations placed on the configured bean are ignored. The default for
this value is true. ignore-annotations is also available for the nodes
class, fields, getter, constructor, method, parameter, cross-parameter
and return-value. If not explicitly specified on these levels the
configured bean value applies.
Using Hibernate Validator to Cover Your Validation Needs article states that:
The default for a field is ignore-annotations=”false”. This means
that by default annotations for a field are stronger (this is of
course after you indicated that that the bean itself wont ignore
annotations). If you wont that the XML will be stronger than you have
to indicate that by ignore-annotations=”true”
It seems possible to disable annotation configuration for a specific field which is configured in XML.
Another solution to switch between annotation and XML configuration is to use Grouping constraints.
I'm not sure if anything of the above is of any use for you, but if it is possible I would probably switch to a single configuration (XML, assuming that annotation config comes from external library you cannot modify) and enforce it everywhere instead of relying on undocumented features.
I have a class MyBean with some fields including String "id".
I have a lot of xml-defined beans with IDs.
I want to fill "id" fields of MyBean java objects to xml-specified bean IDs. How to implement this without code duplicaton?
package just.artmmslv.example.MyBean
public class MyBean {
private String id;
private String foo;
//getters, setters, other fields
}
<beans xmlns="foobar+util">
<util:list value-type="just.artmmslv.example.MyBean">
<bean id="exampleBean01" class="just.artmmslv.example.MyBean">
<property name="foo" value="bar"/>
</bean>
<!--Other beans-->
</util:list>
</beans>
So, how to make exampleBean01`s field id to be equal to "exampleBean01" in convenient way?
Make id in MyBean of type String, not int (I see int in your code)
Make MyBean implements BeanNameAware
Implement method setBeanName in MyBean:
#Override
public void setBeanName(String s) {
this.id = s;
}
That's all you need
I think Spring provides a way to do this via BeanNameAware.
Read through: https://docs.spring.io/spring/docs/2.5.x/reference/beans.html#beans-factory-aware-beannameaware
Interface to be implemented by beans that want to be aware of their bean name in a bean factory. Note that it is not usually recommended that an object depend on its bean name, as this represents a potentially brittle dependence on external
configuration, as well as a possibly unnecessary dependence on a Spring API.
I've asked this question in my previous post here: SpEL for spring security: Passing Values from XML to Java based SpEL configuration. But it wasn't yet resolved. I want to inject values either from an xml configuration or from external file into #PreAuthorize(...) annotation. It is not easy like injecting by using #Value annotation.
To recall the question, I provide the following information.
I have the following xml configuration file (example.xml) that
has properties and initialized its corresponding values.
<beans>
<bean id="userBean" class="x.y.User">
<property name="name" value="A"/>
<property name="userId" value="33"/>
<bean id="customerBean" class="x.y.Customer">
<property name="name" value="B"/>
<property name="customerId" value="33"/>
</bean>
</beans>
I have the following external properties file
(example.properties) inside /WEB-INF folder. This file is an
alternative for the XML configuration file mentioned above.
user.id = 33
customer.id =33
I have property policy holder configuration in my applicationContext.xml file
<context:property-placeholder location="/WEB-INF/*.properties" ignore-unresolvable="true" />
<bean id="propertyConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="/WEB-INF/example.properties" p:ignoreUnresolvablePlaceholders="true" />
I have two model classes: User and Customer
public class User {
private int userId;
public int getUserId() {
return userId;
}
}
public class Customer {
private int customerId;
public int getCustomerId(){
return customerId;
}
}
I have another service/controller class which I want to restrict
the 'edit' method by using #PreAuthorize annotation.
The restriction: The method is allowed (authorized to be executed)
if and only if 'userId' and 'customerId' are evaluated equal!.
To achieve the restriction, I want to consider two ways
by injecting 'userId' and 'customerId' values from the xml file(example.xml) into expression 1 below. The expressions I used in
this are suggested by Rob Winch (Thank you Rob!). However, Spring
couldn't evaluate the expression.
by injecting 'userId' and 'customerId' values from the external properties file(example.properties) into expression 2
below. Similarly, spring couldn't evaluate this expression as well.
#Service("..") or #Controller
public class MyMainClass {
//Expression 1
#PreAuthorize("#userBean.userId == #customerBean.customerId")
public Boolean edit(User user, Customer custmer) {
return true;
}
//Expression 2
////I've tried other ways as well, but end up with similar exceptions
#PreAuthorize("${user.id} == ${customer.id}")
public Boolean edit(User user, Customer customer) {
return true;
}
}
My questions:
Q1. What are the right expressions that I must put inside the #PreAuthorize annotation to inject values from the xml file (example.xml) or from property file (example.properties) into the #PreAuthorize(...) expression, then it can be easily evaluated?
Q2. Point me if I did mistakes other than the expressions.
Q3. Its like a $1,000,000.00 question for me as I am fed up as hell to solve this issue!!!. So please help me out as much as you can!.
if you are using properties file and you want to access them in controller classes you have to add <context:property-placeholder location="classpath:my.properties"/> in your servlet context xml file, after that you can use #Value annotation to get the values of that properties. e.g.
my.properties file contains some.userid=33 so you would access this property using:
#Value("${some.userid}")
private int someId;
but to be sure for testing purpose i would set ignoreUnresolvablePlaceholders to false and in case it can't resolve properties file i would know where the error is coming from...
hope it helps.
I am currently trying to replace my own database controller implementation with Hibernate and I have the following problem creating an appropriate mapping file.
(I am very new to Hibernate, so please be gentle :-) - I've read through the whole Hibernate Reference documentation but I don't have any practical experience yet).
(The whole thing should represent the relationship between email accounts and their server settings).
I have a class called MailAccount which has 2 properties (see code below):
public class MailAccount{
long id;
IncomingMailServer incomingServer;
OutgoingMailServer outgoingServer;
public MailAccount(){
super();
}
// Getter and setter omitted
}
The server class hierachy looks like this:
MailServer.java
public abstract class MailServer {
String password;
String host;
String username;
String port;
// Getter and setter omitted
}
IncomingMailServer.java
public abstract class IncomingMailServer extends MailServer {
}
OutgoingMailServer.java
public abstract class OutgoingMailServer extends MailServer {
}
Pop3Server.java
public class Pop3Server extends IncomingMailServer{
public Pop3Server(){
super();
}
}
ImapServer.java
public class ImapServer extends IncomingMailServer{
public ImapServer(){
super();
}
}
SmtpServer.java
public class SmtpServer extends OutgoingMailServer{
public SmtpServer(){
super();
}
}
The properties incomingServer and outgoingServer in MailAccount.java of course only hold instances of either Pop3Server, ImapServer (for incomingServer) or SmtpServer (for outgoingServer).
Now, I tried to create the mapping file for MailAccount:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="test.account">
<class name="MailAccount" table="MAILACCOUNTS" dynamic-update="true">
<id name="id" column="MAIL_ACCOUNT_ID">
<generator class="native" />
</id>
<component name="incomingServer" class="test.server.incoming.IncomingMailServer">
<property name="password" column="INCOMING_SERVER_PASSWORD" />
<property name="host" column="INCOMING_SERVER_PASSWORD" />
<property name="username" column="INCOMING_SERVER_PASSWORD" />
<property name="port" column="INCOMING_SERVER_PASSWORD" />
</component>
<component name="outgoingServer" class="test.server.outgoing.OutgoingMailServer">
<property name="password" column="OUTGOING_SERVER_PASSWORD" />
<property name="host" column="OUTGOING_SERVER_PASSWORD" />
<property name="username" column="OUTGOING_SERVER_PASSWORD" />
<property name="port" column="OUTGOING_SERVER_PASSWORD" />
</component>
</class>
</hibernate-mapping>
Note: Since I got a 1:1 relation between MailAccount and IncomingMailServer as well as MailAccount and OutgoingMailServer, I want everything in 1 table in order to prevent unnecessary joins.
The problem: Whenever I tell Hibernate to save an instance of MailAccount, like this:
session = getSession();
transaction = session.beginTransaction();
session.save(mailAccount);
transaction.commit();
.. I get the following exception:
org.hibernate.InstantiationException:
Cannot instantiate abstract class or
interface:
test.server.incoming.IncomingMailServer
This totally makes sense since abstract classes cannot be instantiated.
However, here comes my question: How can I tell Hibernate to create an instance of the right class (Pop3Server, SmtpServer, ImapServer) instead of the abstract ones?
Example: If the property incomingServer holds an instance of Pop3Server, then Hiberante should store that into my database and when I load the according MailAccount back, I want Hibernate to recreate an instance of Pop3Server.
The problem is occurring because a component is not a stand-alone entity, but "a class whose instances are stored as an intrinsic part of an owning entity and share the identity of the entity". In JPA terms it is considered an Embeddable class. These classes are usually used to create a class object out of a number of table columns that would normally have to be stored as individual attributes in an entity (you can almost look at it as grouping).
While there are a number of benefits to this approach, there are some restrictions. One of these restrictions are that the component or embeddable cannot be an abstract class. The reason being that there isn't any way for hibernate to associate a particular concrete subclass with the value you are trying to store or read. Think of it this way: would you be able to tell what instance to create by only looking at the column data? It's usually not that straight forward, especially for the persistence engine.
In order to get the functionality you desire, you will want to look into storing MailServer data as a separate entity with its own primary key field. Doing so allows you to manage the data with subclasses using various inheritance methods such as including a DiscriminatorColumn or separate tables (depending on your configuration).
Here are some links that should help you with setting up these mappings and using entity inheritance:
One-to-One mapping example
(useful if not reusing MailServer
data.
Inheritance overview
Useful Hibernate examples (not
latest spec, but gives you good
overview)
Hope this helps.
http://www.vaannila.com/hibernate/hibernate-example/hibernate-example.html
If you were to use this approach using Hibernate (I personally prefer JPA-based Annotation configurations), you could configure MailServer as an abstract entity that would define the common column mappings between the classes and a DiscriminatorColumn (if using same table inheritance). The subclasses would be built off of this definition, adding custom attributes as needed.
It is often useful to have a field in a DAO whose value comes from a Java enumeration. A typical example is a login DAO where you usually have a field that characterises the user as "NORMAL" or "ADMIN". In Hibernate, I would use the following 2 objects to represent this relationship in a (semi-)typesafe way:
class User {
String username;
String passwd;
UserType type;
}
class UserType {
private enum Type {ADMIN, NORMAL};
private String type;
//Setters/Getters for Hibernate
public void setType(String type);
public String getType();
//Setters/Getters for user
public void setUserType(UserType.Type t);
public UserType.Type getUserType();
public static UserType fromType(UserType.Type t);
}
This works, but I find the UserType class ungly and requiring too much bureaucracy just to store a couple of values. Ideally, Hibernate should support enum fields directly and would create an extra table to store the enumeration values.
My question is: Is there any way to directly map an enumeration class in Hibernate? If not, is my pattern for representing enumerations good enough or am I missing something? What other patterns do people use?
using hibernate or JPA annotations:
class User {
#Enumerated(EnumType.STRING)
UserType type
}
UserType is just a standard java 5 enum.
I can't imagine this is just limited to just annotations but I don't actually know how to do this with hbm files. It may be very version dependant, I'm guessing but I'm pretty sure that hibernate 3.2+ is required.
edit: it is possible in a hbm, but is a little messy, have a look at this forum thread
From the Hibernate documentation: http://www.hibernate.org/272.html
You can create a new typedef for each of your enums and reference the typedefs in the property tag.
Example Mapping - inline <type> tag
<property name='suit'>
<type name="EnumUserType">
<param name="enumClassName">com.company.project.Suit</param>
</type>
</property>
Example Mapping - using <typedef>
<typedef name="suit" class='EnumUserType'>
<param name="enumClassName">com.company.project.Suit</param>
</typedef>
<class ...>
<property name='suit' type='suit'/>
</class>