Skip to content

Commit

Permalink
HV-1485 Make ConstraintViolationImpl serializable again
Browse files Browse the repository at this point in the history
Also improves the test around ConstraintViolationImpl serializability.
  • Loading branch information
gsmet authored and gunnarmorling committed Sep 21, 2017
1 parent 1143e72 commit 03e43de
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 10 deletions.
Expand Up @@ -6,7 +6,6 @@
*/
package org.hibernate.validator.internal.engine.constraintvalidation;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.EnumSet;
Expand All @@ -23,7 +22,7 @@
*
* @author Gunnar Morling
*/
public interface ConstraintValidatorDescriptor<A extends Annotation> extends Serializable {
public interface ConstraintValidatorDescriptor<A extends Annotation> {

/**
* The implementation type of the represented validator.
Expand Down
Expand Up @@ -106,8 +106,12 @@ public class ConstraintDescriptorImpl<T extends Annotation> implements Constrain
@Immutable
private final List<Class<? extends ConstraintValidator<T, ?>>> constraintValidatorClasses;

/**
* This field is transient as the implementations of {@link ConstraintValidatorDescriptor} might not be serializable.
* Typically {@code ClassBasedValidatorDescriptor} might contain a {@code ParameterizedTypeImpl}, which is not serializable.
*/
@Immutable
private final List<ConstraintValidatorDescriptor<T>> matchingConstraintValidatorDescriptors;
private final transient List<ConstraintValidatorDescriptor<T>> matchingConstraintValidatorDescriptors;

/**
* The groups for which to apply this constraint.
Expand Down
Expand Up @@ -7,7 +7,10 @@
package org.hibernate.validator.test.internal.engine.serialization;

import static org.hibernate.validator.testutil.ConstraintViolationAssert.assertThat;
import static org.hibernate.validator.testutil.ConstraintViolationAssert.pathWith;
import static org.hibernate.validator.testutil.ConstraintViolationAssert.violationOf;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
Expand All @@ -19,30 +22,76 @@

import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.validation.executable.ExecutableValidator;
import javax.validation.groups.Default;
import javax.validation.metadata.ConstraintDescriptor;
import javax.validation.metadata.ValidateUnwrappedValue;

import org.hibernate.validator.internal.constraintvalidators.bv.size.SizeValidatorForCharSequence;
import org.hibernate.validator.internal.util.CollectionHelper;
import org.hibernate.validator.test.internal.engine.serialization.SerializableClass.TestPayload;
import org.hibernate.validator.testutil.TestForIssue;
import org.hibernate.validator.testutils.ValidatorUtil;

import org.testng.annotations.Test;

/**
* @author Hardy Ferentschik
* @author Guillaume Smet
*/
public class ConstraintViolationSerializationTest {

@Test
@TestForIssue(jiraKey = "HV-245")
@TestForIssue(jiraKey = { "HV-245", "HV-1485" })
public void testSuccessfulSerialization() throws Exception {
Validator validator = ValidatorUtil.getValidator();
SerializableClass testInstance = new SerializableClass();
SerializableClass testInstance = new SerializableClass( "s" );
Set<ConstraintViolation<SerializableClass>> constraintViolations = validator.validate( testInstance );

byte[] bytes = serialize( constraintViolations );
Set<ConstraintViolation<?>> deserializedViolations = deserialize( bytes );
assertThat( deserializedViolations ).containsOnlyViolations(
violationOf( NotNull.class ).withProperty( "foo" )
violationOf( Size.class )
.withProperty( "foo" )
);

checkSerializedViolation( deserializedViolations.iterator().next(), testInstance, null, null );
}

@Test
@TestForIssue(jiraKey = "HV-1485")
public void testSuccessfulSerializationWithMethodParameters() throws Exception {
ExecutableValidator validator = ValidatorUtil.getValidator().forExecutables();
SerializableClass testInstance = new SerializableClass( "s" );
Set<ConstraintViolation<SerializableClass>> constraintViolations = validator.validateParameters( testInstance,
SerializableClass.class.getMethod( "fooParameter", String.class ), new Object[] { "s" } );

byte[] bytes = serialize( constraintViolations );
Set<ConstraintViolation<?>> deserializedViolations = deserialize( bytes );
assertThat( deserializedViolations ).containsOnlyViolations(
violationOf( Size.class ).withPropertyPath( pathWith()
.method( "fooParameter" )
.parameter( "foo", 0 ) ) );

checkSerializedViolation( deserializedViolations.iterator().next(), testInstance, new Object[] { "s" }, null );
}

@Test
@TestForIssue(jiraKey = "HV-1485")
public void testSuccessfulSerializationWithMethodReturnValue() throws Exception {
ExecutableValidator validator = ValidatorUtil.getValidator().forExecutables();
SerializableClass testInstance = new SerializableClass( "s" );
Set<ConstraintViolation<SerializableClass>> constraintViolations = validator.validateReturnValue( testInstance,
SerializableClass.class.getMethod( "fooReturnValue" ), "s" );

byte[] bytes = serialize( constraintViolations );
Set<ConstraintViolation<?>> deserializedViolations = deserialize( bytes );
assertThat( deserializedViolations ).containsOnlyViolations(
violationOf( Size.class ).withPropertyPath( pathWith()
.method( "fooReturnValue" )
.returnValue() ) );

checkSerializedViolation( deserializedViolations.iterator().next(), testInstance, null, "s" );
}

@TestForIssue(jiraKey = "HV-245")
Expand Down Expand Up @@ -75,4 +124,25 @@ private Set<ConstraintViolation<?>> deserialize(byte[] byteData) throws Exceptio
byteIn.close();
return deserializedViolations;
}

private void checkSerializedViolation(ConstraintViolation<?> constraintViolation, SerializableClass testInstance, Object[] executableParameters,
Object executableReturnValue) {
assertEquals( constraintViolation.getLeafBean(), testInstance );
assertEquals( constraintViolation.getRootBean(), testInstance );
assertEquals( constraintViolation.getRootBeanClass(), SerializableClass.class );
assertEquals( constraintViolation.getMessage(), "size must be between 5 and 2147483647" );
assertEquals( constraintViolation.getMessageTemplate(), "{javax.validation.constraints.Size.message}" );
assertEquals( constraintViolation.getInvalidValue(), "s" );
assertEquals( constraintViolation.getExecutableParameters(), executableParameters );
assertEquals( constraintViolation.getExecutableReturnValue(), executableReturnValue );

ConstraintDescriptor<?> constraintDescriptor = constraintViolation.getConstraintDescriptor();
assertEquals( constraintDescriptor.getAnnotation().annotationType(), Size.class );
assertEquals( constraintDescriptor.getGroups(), CollectionHelper.asSet( Default.class ) );
assertEquals( constraintDescriptor.getMessageTemplate(), "{javax.validation.constraints.Size.message}" );
assertEquals( constraintDescriptor.getPayload(), CollectionHelper.asSet( TestPayload.class ) );
assertEquals( constraintDescriptor.getValidationAppliesTo(), null );
assertEquals( constraintDescriptor.getValueUnwrapping(), ValidateUnwrappedValue.DEFAULT );
assertTrue( constraintDescriptor.getConstraintValidatorClasses().contains( SizeValidatorForCharSequence.class ) );
}
}
Expand Up @@ -7,12 +7,51 @@
package org.hibernate.validator.test.internal.engine.serialization;

import java.io.Serializable;
import javax.validation.constraints.NotNull;
import java.util.Objects;

import javax.validation.Payload;
import javax.validation.constraints.Size;

/**
* @author Hardy Ferentschik
* @author Guillaume Smet
*/
public class SerializableClass implements Serializable {
@NotNull

@Size(min = 5, payload = TestPayload.class)
private String foo;

public SerializableClass(String foo) {
this.foo = foo;
}

public void fooParameter(@Size(min = 5, payload = TestPayload.class) String foo) {
}

@Size(min = 5, payload = TestPayload.class)
public String fooReturnValue() {
return foo;
}

@Override
public boolean equals(Object obj) {
if ( obj == null ) {
return false;
}
if ( getClass() != obj.getClass() ) {
return false;
}

SerializableClass other = (SerializableClass) obj;

return Objects.equals( foo, other.foo );
}

@Override
public int hashCode() {
return Objects.hash( foo );
}

public static class TestPayload implements Payload {
}
}

0 comments on commit 03e43de

Please sign in to comment.