diff --git a/hibernate-core/src/main/java/org/hibernate/internal/FilterImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/FilterImpl.java index ec35374aa238..bcb767f83f01 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/FilterImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/FilterImpl.java @@ -37,9 +37,11 @@ public class FilterImpl implements Filter, Serializable { private @Nullable TreeMap parameters; private final boolean autoEnabled; private final boolean applyToLoadByKey; + private transient boolean validated; void afterDeserialize(SessionFactoryImplementor factory) { definition = factory.getFilterDefinition( filterName ); + validated = false; validate(); } @@ -117,6 +119,7 @@ public Filter setParameter(String name, Object value) throws IllegalArgumentExce parameters = new TreeMap<>(); } parameters.put( name, argument ); + validated = false; return this; } @@ -148,6 +151,7 @@ public Filter setParameterList(String name, Collection values) throws Hiberna parameters = new TreeMap<>(); } parameters.put( name, values ); + validated = false; return this; } @@ -184,6 +188,9 @@ public Supplier getParameterResolver(String name) { * @throws HibernateException If the state is not currently valid. */ public void validate() throws HibernateException { + if ( validated ) { + return; + } // for each of the defined parameters, make sure its argument // has been set or a resolver has been implemented and specified for ( final String parameterName : definition.getParameterNames() ) { @@ -192,6 +199,7 @@ public void validate() throws HibernateException { + "' has neither an argument nor a resolver" ); } } + validated = true; } private boolean hasResolver(String parameterName) { diff --git a/hibernate-core/src/test/java/org/hibernate/internal/FilterImplSerializationTest.java b/hibernate-core/src/test/java/org/hibernate/internal/FilterImplSerializationTest.java new file mode 100644 index 000000000000..c91eb426f3da --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/internal/FilterImplSerializationTest.java @@ -0,0 +1,71 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.internal; + +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import org.hibernate.engine.spi.FilterDefinition; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.internal.util.SerializationHelper; +import org.hibernate.metamodel.mapping.JdbcMapping; +import org.hibernate.type.StandardBasicTypes; +import org.hibernate.type.spi.TypeConfiguration; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class FilterImplSerializationTest { + + @Test + public void testValidateAfterDeserialize() throws Exception { + final FilterDefinition definition = buildDefinition(); + final FilterImpl filter = new FilterImpl( definition ); + filter.setParameter( "param", "value" ); + filter.validate(); + + final FilterImpl deserialized = (FilterImpl) SerializationHelper.deserialize( + SerializationHelper.serialize( filter ), + FilterImpl.class.getClassLoader() + ); + + assertThat( readValidated( deserialized ) ).isFalse(); + + final SessionFactoryImplementor factory = mock( SessionFactoryImplementor.class ); + when( factory.getFilterDefinition( "testFilter" ) ).thenReturn( definition ); + + deserialized.afterDeserialize( factory ); + + assertThat( readValidated( deserialized ) ).isTrue(); + deserialized.setParameter( "param", "updated" ); + assertThat( readValidated( deserialized ) ).isFalse(); + deserialized.validate(); + assertThat( readValidated( deserialized ) ).isTrue(); + deserialized.setParameterList( "param", Arrays.asList( "list-value" ) ); + assertThat( readValidated( deserialized ) ).isFalse(); + deserialized.validate(); + assertThat( readValidated( deserialized ) ).isTrue(); + } + + private static FilterDefinition buildDefinition() { + final TypeConfiguration typeConfiguration = new TypeConfiguration(); + final JdbcMapping mapping = + typeConfiguration.getBasicTypeRegistry().resolve( StandardBasicTypes.STRING ); + final Map paramMappings = new HashMap<>(); + paramMappings.put( "param", mapping ); + return new FilterDefinition( "testFilter", "col = :param", paramMappings ); + } + + private static boolean readValidated(FilterImpl filter) throws Exception { + final Field validatedField = FilterImpl.class.getDeclaredField( "validated" ); + validatedField.setAccessible( true ); + return validatedField.getBoolean( filter ); + } + +}