Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [bean-validation-dev] Provides a way to implement a dynamic clock provider?

Sorry for my negligence, just having the validation object is not enough, more information is needed:

package jakarta.validation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.time.Clock;
public interface DynamicClockProvider {
    /**
     * Returns the clock which serves as the reference for {@code now}.
     * <p>
     * Ensure that the {@link Clock} used as the reference for {@code now} is obtained
     * for each verification of {@code @Future}, {@code @FutureOrPresent}, {@code @Past},
     * and {@code @PastOrPresent} constraints.
     *
     * @param fieldHolder if the validation object is a field value of a class, then this
     *                    will be the instance that holds the value of this field
     * @param field if the validation object is a field value of a class, then this will
     *              be the class's field reflection object
     * @param method if the validation object is a method parameter or return, then this
     *               will be the reflection object of this method
     * @param object object to validate
     * @param groups the group or list of groups targeted for validation (defaults to
     *        {@link jakarta.validation.groups.Default Default})
     * @param <T> the type of the object to validate
     * @return the clock which serves as the reference for {@code now}; must not be
     * {@code null}
     *
     * @since 4.0
     */
    <T> Clock getClock(Object fieldHolder,
                       Field field,
                       Method method,
                       T object,
                       Class<?>... groups);
}


Kind regards,
Xi Minghui

On 10/15/2024 9:30 PM, Xi Minghui wrote:
Hi,

I'm trying to implement a solution that dynamically decides which Clock to provide based on the object currently being validated, but the current ClockProvider contract doesn't support this.

I thought about implementing it through the ThreadLocal mechanism, but this would mean that validation relies on threads, and to support asynchronous or concurrent execution, more work would be required, which would increase complexity. I believe the most direct, effective, and simple approach is to pass the current validation object to the ClockProvider, like: change java.time.Clock getClock() to <T> java.time.Clock getClock(T object, Class<?>... groups).


Points to consider for the change:

- Keep functional interface: Ideally, ClockProvider should still be usable with lambda expressions.
- Consider backward compatibility: Think about the pain of code migration, especially with lambda method references.


Proposed Approach 1: Add a New Interface

package jakarta.validation;
import java.time.Clock;
public interface DynamicClockProvider {
    /**
     * Returns the clock which serves as the reference for {@code now}.
     * <p>
     * Ensure that the {@link Clock} used as the reference for {@code now} is obtained
     * for each verification of {@code @Future}, {@code @FutureOrPresent}, {@code @Past},
     * and {@code @PastOrPresent} constraints.
     *
     * @param object object to validate
     * @param groups the group or list of groups targeted for validation (defaults to
     *        {@link jakarta.validation.groups.Default Default})
     * @param <T> the type of the object to validate
     * @return the clock which serves as the reference for {@code now}; must not be
     * {@code null}
     *
     * @since 4.0
     */
    <T> Clock getClock(T object, Class<?>... groups);
}


Proposed Approach 2: Update the ClockProvider

/*
 * Jakarta Validation API
 *
 * License: Apache License, Version 2.0
 * See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.
 */
package jakarta.validation;
import java.time.Clock;
/**
 * Contract for obtaining the {@link Clock} used as the reference for {@code now} when
 * validating the {@code @Future}, {@code FutureOrPresent}, {@code Past}, and
 * {@code @PastOrPresent} constraints.
 * <p>
 * The default implementation will return the current system time. Plugging in custom
 * implementations may be useful for instance in batch applications which need to run with a
 * specific logical date, e.g. with yesterday's date when re-running a failed batch job
 * execution.
 * <p>
 * Implementations must be safe for access from several threads at the same time.
 *
 * @author Gunnar Morling
 * @author Guillaume Smet
 * @since 2.0
 */
public interface ClockProvider {
    /**
     * Returns the clock which serves as the reference for {@code now}.
     * <p>
     * Ensure that the {@link Clock} used as the reference for {@code now} is obtained
     * for each verification of {@code @Future}, {@code @FutureOrPresent}, {@code @Past},
     * and {@code @PastOrPresent} constraints.
     *
     * @param object object to validate
     * @param groups the group or list of groups targeted for validation (defaults to
     *        {@link jakarta.validation.groups.Default Default})
     * @param <T> the type of the object to validate
     * @return the clock which serves as the reference for {@code now}; must not be
     * {@code null}
     *
     * @since 4.0
     */
    <T> Clock getClock(T object, Class<?>... groups);
}


What do you think of this? I would greatly appreciate your feedback and any other ideas you might have.

Kind regards,
Xi Minghui


Back to the top