Author: hardy.ferentschik
Date: 2010-03-08 16:52:30 -0500 (Mon, 08 Mar 2010)
New Revision: 18937
Added:
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/serialization/CustomConstraintSerializableTest.java
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/serialization/DummyEmailValidator.java
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/serialization/Email.java
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/util/annotationfactory/AnnotationProxy.java
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/util/TestUtil.java
Log:
HV-291 Made sure AnnotationProxy serializable. Note, it is still not guaranteed that the
ConstraintViolation will be serializable since it might contain unserailizable
information.
Modified:
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/util/annotationfactory/AnnotationProxy.java
===================================================================
---
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/util/annotationfactory/AnnotationProxy.java 2010-03-08
21:18:03 UTC (rev 18936)
+++
validator/trunk/hibernate-validator/src/main/java/org/hibernate/validator/util/annotationfactory/AnnotationProxy.java 2010-03-08
21:52:30 UTC (rev 18937)
@@ -17,15 +17,15 @@
*/
package org.hibernate.validator.util.annotationfactory;
+import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
-import java.util.Comparator;
+import java.security.AccessController;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
-import java.security.AccessController;
import org.hibernate.validator.util.GetDeclaredMethods;
@@ -53,21 +53,20 @@
* @author Davide Marchignoli
* @see java.lang.annotation.Annotation
*/
-public class AnnotationProxy implements Annotation, InvocationHandler {
+public class AnnotationProxy implements Annotation, InvocationHandler, Serializable {
+ private static final long serialVersionUID = 6907601010599429454L;
private final Class<? extends Annotation> annotationType;
- //FIXME it's probably better to use String as a key rather than Method
- // to speed up and avoid any fancy permsize/GC issue
- // I'd better check the litterature on the subject
- private final Map<Method, Object> values;
+ private final Map<String, Object> values;
+
public AnnotationProxy(AnnotationDescriptor descriptor) {
this.annotationType = descriptor.type();
values = getAnnotationValues( descriptor );
}
- private Map<Method, Object> getAnnotationValues(AnnotationDescriptor descriptor)
{
- Map<Method, Object> result = new HashMap<Method, Object>();
+ private Map<String, Object> getAnnotationValues(AnnotationDescriptor descriptor)
{
+ Map<String, Object> result = new HashMap<String, Object>();
int processedValuesFromDescriptor = 0;
GetDeclaredMethods action = GetDeclaredMethods.action( annotationType );
final Method[] declaredMethods;
@@ -79,25 +78,25 @@
}
for ( Method m : declaredMethods ) {
if ( descriptor.containsElement( m.getName() ) ) {
- result.put( m, descriptor.valueOf( m.getName() ) );
+ result.put( m.getName(), descriptor.valueOf( m.getName() ) );
processedValuesFromDescriptor++;
}
else if ( m.getDefaultValue() != null ) {
- result.put( m, m.getDefaultValue() );
+ result.put( m.getName(), m.getDefaultValue() );
}
else {
throw new IllegalArgumentException( "No value provided for " + m.getName()
);
}
}
if ( processedValuesFromDescriptor != descriptor.numberOfElements() ) {
- throw new RuntimeException( "Trying to instanciate " + annotationType +
" with unknown paramters." );
+ throw new RuntimeException( "Trying to instantiate " + annotationType +
" with unknown paramters." );
}
return result;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- if ( values.containsKey( method ) ) {
- return values.get( method );
+ if ( values.containsKey( method.getName() ) ) {
+ return values.get( method.getName() );
}
return method.invoke( this, args );
}
@@ -109,8 +108,8 @@
public String toString() {
StringBuilder result = new StringBuilder();
result.append( '@' ).append( annotationType().getName() ).append( '('
);
- for ( Method m : getRegisteredMethodsInAlphabeticalOrder() ) {
- result.append( m.getName() ).append( '=' ).append( values.get( m ) ).append(
", " );
+ for ( String s : getRegisteredMethodsInAlphabeticalOrder() ) {
+ result.append( s ).append( '=' ).append( values.get( s ) ).append( ",
" );
}
// remove last separator:
if ( values.size() > 0 ) {
@@ -124,15 +123,8 @@
return result.toString();
}
- private SortedSet<Method> getRegisteredMethodsInAlphabeticalOrder() {
- SortedSet<Method> result = new TreeSet<Method>(
- new Comparator<Method>() {
- public int compare(Method o1, Method o2) {
- return o1.getName().compareTo( o2.getName() );
- }
- }
- );
- //List<Method> result = new LinkedList<Method>();
+ private SortedSet<String> getRegisteredMethodsInAlphabeticalOrder() {
+ SortedSet<String> result = new TreeSet<String>();
result.addAll( values.keySet() );
return result;
}
Added:
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/serialization/CustomConstraintSerializableTest.java
===================================================================
---
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/serialization/CustomConstraintSerializableTest.java
(rev 0)
+++
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/serialization/CustomConstraintSerializableTest.java 2010-03-08
21:52:30 UTC (rev 18937)
@@ -0,0 +1,99 @@
+// $Id:$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat, Inc. and/or its affiliates, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
http://www.apache.org/licenses/LICENSE-2.0
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.hibernate.validator.engine.serialization;
+
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.Set;
+import javax.validation.ConstraintViolation;
+import javax.validation.Validator;
+
+import org.testng.annotations.Test;
+
+import org.hibernate.validator.util.TestUtil;
+
+
+/**
+ * A <b>sscce</b> (Short, Self Contained, Correct Example) showing that the
+ * simple custom Email validation constraint taken from <a
href="http://blog.jteam.nl/2009/08/04/bean-validation-integrating-jsr-303-with-spring/"
+ * >this blog</a> gives a validation result that is not Serializable with
+ * Hibernate Validator 4.0.2.GA with underlying cause that
+ * <p/>
+ *
<code>org.hibernate.validator.util.annotationfactory.AnnotationProxy</code>
+ * <p/>
+ * <p/>
+ * Note that Hibernate Validator does not guarantee at all that a
+ * {@link ConstraintViolation} is Serializable because an entity need not be
+ * Serializable, but otherwise there should not be much of a problem (right?).
+ *
+ * @author Henno Vermeulen
+ * @author Hardy Ferentschik
+ */
+public class CustomConstraintSerializableTest {
+
+ @Test
+ public void testSerializeHibernateEmail() throws Exception {
+ Validator validator = TestUtil.getValidator();
+
+ HibernateEmail invalidHibernateEmail = new HibernateEmail();
+ invalidHibernateEmail.email = "test@";
+
+ Set<ConstraintViolation<HibernateEmail>> constraintViolations =
validator.validate( invalidHibernateEmail );
+ doSerialize( constraintViolations.iterator().next() );
+ }
+
+ /**
+ * HV-291
+ *
+ * @throws Exception in case the test fails
+ */
+ @Test
+ public void testSerializeCustomEmail() throws Exception {
+ Validator validator = TestUtil.getValidator();
+
+ CustomEmail invalidCustomEmail = new CustomEmail();
+ invalidCustomEmail.email = "test@";
+ Set<ConstraintViolation<CustomEmail>> constraintViolations =
validator.validate( invalidCustomEmail );
+ doSerialize( constraintViolations.iterator().next() );
+ }
+
+ public static byte[] doSerialize(Object obj) throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream( 512 );
+ ObjectOutputStream out = new ObjectOutputStream( baos );
+ out.writeObject( obj );
+ out.close();
+ return baos.toByteArray();
+ }
+
+ static class CustomEmail implements Serializable {
+ private static final long serialVersionUID = -9095271389455131159L;
+
+ @Email
+ String email;
+
+ }
+
+ static class HibernateEmail implements Serializable {
+ private static final long serialVersionUID = 7206154160792549270L;
+
+ @org.hibernate.validator.constraints.Email
+ String email;
+ }
+}
+
Property changes on:
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/serialization/CustomConstraintSerializableTest.java
___________________________________________________________________
Name: svn:keywords
+ Id
Added:
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/serialization/DummyEmailValidator.java
===================================================================
---
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/serialization/DummyEmailValidator.java
(rev 0)
+++
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/serialization/DummyEmailValidator.java 2010-03-08
21:52:30 UTC (rev 18937)
@@ -0,0 +1,35 @@
+// $Id:$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat, Inc. and/or its affiliates, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
http://www.apache.org/licenses/LICENSE-2.0
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.hibernate.validator.engine.serialization;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+/**
+ * @author Hardy Ferentschik
+ */
+public class DummyEmailValidator implements ConstraintValidator<Email, String> {
+ public void initialize(Email annotation) {
+ }
+
+ public boolean isValid(String value, ConstraintValidatorContext context) {
+ return false;
+ }
+}
+
+
Property changes on:
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/serialization/DummyEmailValidator.java
___________________________________________________________________
Name: svn:keywords
+ Id
Added:
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/serialization/Email.java
===================================================================
---
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/serialization/Email.java
(rev 0)
+++
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/serialization/Email.java 2010-03-08
21:52:30 UTC (rev 18937)
@@ -0,0 +1,52 @@
+// $Id:$
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2009, Red Hat, Inc. and/or its affiliates, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
http://www.apache.org/licenses/LICENSE-2.0
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+package org.hibernate.validator.engine.serialization;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import javax.validation.ReportAsSingleViolation;
+import javax.validation.constraints.Pattern;
+
+/**
+ * Denotes that a field should contain a valid email address.
+ * <p/>
+ * <p/>
+ * Taken from <a
href="http://blog.jteam.nl/2009/08/04/bean-validation-integrating-jsr-303-with-spring/"
+ * >this blog</a>.
+ *
+ * @author Hardy Ferentschik
+ */
+@Documented
+@Constraint(validatedBy = { DummyEmailValidator.class })
+@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
+(a)Retention(RetentionPolicy.RUNTIME)
+@Pattern(regexp = ".+@.+\\.[a-z]+")
+@ReportAsSingleViolation
+public @interface Email {
+
+ public abstract String message() default
"{org.hibernate.validator.engine.serialization.Email.message}";
+
+ public abstract Class<?>[] groups() default { };
+
+ public abstract Class<? extends Payload>[] payload() default { };
+}
Property changes on:
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/engine/serialization/Email.java
___________________________________________________________________
Name: svn:keywords
+ Id
Modified:
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/util/TestUtil.java
===================================================================
---
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/util/TestUtil.java 2010-03-08
21:18:03 UTC (rev 18936)
+++
validator/trunk/hibernate-validator/src/test/java/org/hibernate/validator/util/TestUtil.java 2010-03-08
21:52:30 UTC (rev 18937)
@@ -118,7 +118,7 @@
actualMessages.add( violation.getMessage() );
}
- assertTrue( actualMessages.size() == messages.length, "Wrong number or error
messages" );
+ assertTrue( actualMessages.size() == messages.length, "Wrong number of error
messages" );
for ( String expectedMessage : messages ) {
assertTrue(
@@ -128,11 +128,11 @@
actualMessages.remove( expectedMessage );
}
assertTrue(
- actualMessages.isEmpty(), "Actual messages contained more messages as specidied
expected messages"
+ actualMessages.isEmpty(), "Actual messages contained more messages as specified
expected messages"
);
}
- public static <T> void
assertCorrectConstraintTypes(Set<ConstraintViolation<T>> violations,
Class<?>... expectedConsraintTypes) {
+ public static <T> void
assertCorrectConstraintTypes(Set<ConstraintViolation<T>> violations,
Class<?>... expectedConstraintTypes) {
List<String> actualConstraintTypes = new ArrayList<String>();
for ( ConstraintViolation<?> violation : violations ) {
actualConstraintTypes.add(
@@ -141,10 +141,10 @@
}
assertEquals(
- expectedConsraintTypes.length, actualConstraintTypes.size(), "Wrong number of
constraint types."
+ expectedConstraintTypes.length, actualConstraintTypes.size(), "Wrong number of
constraint types."
);
- for ( Class<?> expectedConstraintType : expectedConsraintTypes ) {
+ for ( Class<?> expectedConstraintType : expectedConstraintTypes ) {
assertTrue(
actualConstraintTypes.contains( expectedConstraintType.getName() ),
"The constraint type " + expectedConstraintType.getName() + " should
have been violated."