View Javadoc
1   /*
2    * Copyright (c) 2012-2024, jcabi.com
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met: 1) Redistributions of source code must retain the above
8    * copyright notice, this list of conditions and the following
9    * disclaimer. 2) Redistributions in binary form must reproduce the above
10   * copyright notice, this list of conditions and the following
11   * disclaimer in the documentation and/or other materials provided
12   * with the distribution. 3) Neither the name of the jcabi.com nor
13   * the names of its contributors may be used to endorse or promote
14   * products derived from this software without specific prior written
15   * permission.
16   *
17   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
19   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21   * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28   * OF THE POSSIBILITY OF SUCH DAMAGE.
29   */
30  package com.jcabi.aspects;
31  
32  import java.io.InputStream;
33  import java.lang.annotation.Annotation;
34  import java.lang.annotation.ElementType;
35  import java.lang.reflect.Constructor;
36  import java.lang.reflect.InvocationTargetException;
37  import java.lang.reflect.Method;
38  import java.time.Clock;
39  import java.util.Collections;
40  import java.util.HashSet;
41  import java.util.List;
42  import java.util.Locale;
43  import java.util.Set;
44  import javax.validation.BootstrapConfiguration;
45  import javax.validation.ClockProvider;
46  import javax.validation.Configuration;
47  import javax.validation.ConstraintValidator;
48  import javax.validation.ConstraintValidatorContext;
49  import javax.validation.ConstraintValidatorFactory;
50  import javax.validation.ConstraintViolation;
51  import javax.validation.MessageInterpolator;
52  import javax.validation.ParameterNameProvider;
53  import javax.validation.Path;
54  import javax.validation.TraversableResolver;
55  import javax.validation.Validator;
56  import javax.validation.ValidatorContext;
57  import javax.validation.ValidatorFactory;
58  import javax.validation.executable.ExecutableValidator;
59  import javax.validation.metadata.BeanDescriptor;
60  import javax.validation.spi.BootstrapState;
61  import javax.validation.spi.ConfigurationState;
62  import javax.validation.spi.ValidationProvider;
63  import javax.validation.valueextraction.ValueExtractor;
64  
65  /**
66   * Fake validation provider for JSR-303.
67   *
68   * This class can help when it's necessary to disable the entire JSR-303 validation
69   * mechanism, but it's impossible to take certain classes from the classpath, which
70   * are using JSR-303 and demand the presence of a validator.
71   *
72   * A text resource <tt>META-INF/services/javax.validation.spi.ValidationProvider</tt>
73   * must be created, with a single line inside:
74   * <tt>com.jcabi.aspects.FakeValidationProvider</tt>. Once this file is found
75   * in the classpath, JSR-303 engine will use this fake validator provider and no constraints
76   * will be reported in runtime.
77   *
78   * @since 0.25.0
79   */
80  @SuppressWarnings("PMD.ExcessivePublicCount")
81  public final class FakeValidationProvider implements
82      ValidationProvider<FakeValidationProvider.FakeConfiguration> {
83  
84      @Override
85      public FakeConfiguration createSpecializedConfiguration(final BootstrapState state) {
86          return new FakeValidationProvider.FakeConfiguration();
87      }
88  
89      @Override
90      public Configuration<?> createGenericConfiguration(final BootstrapState state) {
91          return new FakeValidationProvider.FakeConfiguration();
92      }
93  
94      @Override
95      public ValidatorFactory buildValidatorFactory(final ConfigurationState state) {
96          return new FakeValidationProvider.FakeValidatorFactory();
97      }
98  
99      /**
100      * Fake class.
101      *
102      * @since 0.25.0
103      */
104     static class FakeValidatorFactory implements ValidatorFactory {
105         @Override
106         public Validator getValidator() {
107             return new FakeValidationProvider.FakeValidator();
108         }
109 
110         @Override
111         public ValidatorContext usingContext() {
112             return new FakeValidatorContext();
113         }
114 
115         @Override
116         public MessageInterpolator getMessageInterpolator() {
117             return new FakeMessageInterpolator();
118         }
119 
120         @Override
121         public TraversableResolver getTraversableResolver() {
122             return new FakeTraversableResolver();
123         }
124 
125         @Override
126         public ConstraintValidatorFactory getConstraintValidatorFactory() {
127             return new FakeConstraintValidatorFactory();
128         }
129 
130         @Override
131         public ParameterNameProvider getParameterNameProvider() {
132             return new FakeParameterNameProvider();
133         }
134 
135         @Override
136         public ClockProvider getClockProvider() {
137             return new FakeClockProvider();
138         }
139 
140         @Override
141         public <T> T unwrap(final Class<T> clazz) {
142             try {
143                 return clazz.getConstructor().newInstance();
144             } catch (final InstantiationException | IllegalAccessException
145                 | InvocationTargetException | NoSuchMethodException ex) {
146                 throw new IllegalArgumentException(ex);
147             }
148         }
149 
150         @Override
151         public void close() {
152             // intentionally empty
153         }
154     }
155 
156     /**
157      * Fake class.
158      *
159      * @since 0.25.0
160      */
161     static final class FakeClockProvider implements ClockProvider {
162         @Override
163         public Clock getClock() {
164             return Clock.systemUTC();
165         }
166     }
167 
168     /**
169      * Fake class.
170      *
171      * @since 0.25.0
172      */
173     static final class FakeParameterNameProvider implements ParameterNameProvider {
174         @Override
175         public List<String> getParameterNames(final Constructor<?> ctor) {
176             return Collections.emptyList();
177         }
178 
179         @Override
180         public List<String> getParameterNames(final Method method) {
181             return Collections.emptyList();
182         }
183     }
184 
185     /**
186      * Fake class.
187      *
188      * @since 0.25.0
189      */
190     static final class FakeConstraintValidatorFactory
191         implements ConstraintValidatorFactory {
192         @Override
193         @SuppressWarnings("PMD.SingletonClassReturningNewInstance")
194         public <T extends ConstraintValidator<?, ?>> T getInstance(final Class<T> clazz) {
195             return clazz.cast(new FakeConstraintValidator<Annotation, String>());
196         }
197 
198         @Override
199         public void releaseInstance(final ConstraintValidator<?, ?> validator) {
200             // intentionally empty
201         }
202     }
203 
204     /**
205      * Fake class.
206      *
207      * @param <T> Type
208      * @param <X> Another type
209      * @since 0.25.0
210      */
211     static final class FakeConstraintValidator<T extends Annotation,
212         X> implements ConstraintValidator<T, X> {
213         @Override
214         public boolean isValid(final Object obj,
215             final ConstraintValidatorContext context) {
216             return true;
217         }
218     }
219 
220     /**
221      * Fake class.
222      *
223      * @since 0.25.0
224      */
225     static final class FakeMessageInterpolator implements MessageInterpolator {
226         @Override
227         public String interpolate(final String str, final Context context) {
228             return "empty";
229         }
230 
231         @Override
232         public String interpolate(final String str, final Context context,
233             final Locale locale) {
234             return "empty";
235         }
236     }
237 
238     /**
239      * Fake class.
240      *
241      * @since 0.25.0
242      */
243     static final class FakeTraversableResolver implements TraversableResolver {
244         @Override
245         public boolean isReachable(final Object obj, final Path.Node node,
246             final Class<?> clazz, final Path path, final ElementType type) {
247             return false;
248         }
249 
250         @Override
251         public boolean isCascadable(final Object obj, final Path.Node node,
252             final Class<?> clazz, final Path path, final ElementType type) {
253             return false;
254         }
255     }
256 
257     /**
258      * Fake class.
259      *
260      * @since 0.25.0
261      */
262     static final class FakeValidatorContext implements ValidatorContext {
263         @Override
264         public ValidatorContext messageInterpolator(final MessageInterpolator inter) {
265             return this;
266         }
267 
268         @Override
269         public ValidatorContext traversableResolver(final TraversableResolver resolver) {
270             return this;
271         }
272 
273         @Override
274         public ValidatorContext constraintValidatorFactory(final
275             ConstraintValidatorFactory factory) {
276             return this;
277         }
278 
279         @Override
280         public ValidatorContext parameterNameProvider(final
281             ParameterNameProvider provider) {
282             return this;
283         }
284 
285         @Override
286         public ValidatorContext clockProvider(final ClockProvider provider) {
287             return this;
288         }
289 
290         @Override
291         public ValidatorContext addValueExtractor(final ValueExtractor<?> extractor) {
292             return this;
293         }
294 
295         @Override
296         public Validator getValidator() {
297             return new FakeValidator();
298         }
299     }
300 
301     /**
302      * Fake class.
303      *
304      * @since 0.25.0
305      */
306     static final class FakeValidator implements Validator {
307         @Override
308         public <T> Set<ConstraintViolation<T>> validate(final T type,
309             final Class<?>... classes) {
310             return new HashSet<>();
311         }
312 
313         @Override
314         public <T> Set<ConstraintViolation<T>> validateProperty(final T type,
315             final String str, final Class<?>... classes) {
316             return new HashSet<>();
317         }
318 
319         @Override
320         public <T> Set<ConstraintViolation<T>> validateValue(final Class<T> clazz,
321             final String str, final Object obj, final Class<?>... classes) {
322             return new HashSet<>();
323         }
324 
325         @Override
326         public BeanDescriptor getConstraintsForClass(final Class<?> clazz) {
327             return null;
328         }
329 
330         @Override
331         public <T> T unwrap(final Class<T> clazz) {
332             try {
333                 return clazz.getConstructor().newInstance();
334             } catch (final InstantiationException | IllegalAccessException
335                 | InvocationTargetException | NoSuchMethodException ex) {
336                 throw new IllegalArgumentException(ex);
337             }
338         }
339 
340         @Override
341         public ExecutableValidator forExecutables() {
342             return new FakeExecutableValidator();
343         }
344     }
345 
346     /**
347      * Fake class.
348      *
349      * @since 0.25.0
350      */
351     static final class FakeExecutableValidator implements ExecutableValidator {
352         @Override
353         public <T> Set<ConstraintViolation<T>> validateParameters(final T type,
354             final Method method, final Object[] objects, final Class<?>... classes) {
355             return new HashSet<>();
356         }
357 
358         @Override
359         public <T> Set<ConstraintViolation<T>> validateReturnValue(final T type,
360             final Method method, final Object obj, final Class<?>... classes) {
361             return new HashSet<>();
362         }
363 
364         @Override
365         public <T> Set<ConstraintViolation<T>> validateConstructorParameters(final
366             Constructor<? extends T> constructor,
367             final Object[] objects, final Class<?>... classes) {
368             return new HashSet<>();
369         }
370 
371         @Override
372         public <T> Set<ConstraintViolation<T>> validateConstructorReturnValue(final
373             Constructor<? extends T> constructor,
374             final T type, final Class<?>... classes) {
375             return new HashSet<>();
376         }
377     }
378 
379     /**
380      * Fake class.
381      *
382      * @since 0.25.0
383      */
384     static final class FakeConfiguration implements Configuration<FakeConfiguration> {
385         @Override
386         public FakeConfiguration ignoreXmlConfiguration() {
387             return this;
388         }
389 
390         @Override
391         public FakeConfiguration messageInterpolator(final MessageInterpolator interpolator) {
392             return this;
393         }
394 
395         @Override
396         public FakeConfiguration traversableResolver(final TraversableResolver resolver) {
397             return this;
398         }
399 
400         @Override
401         public FakeConfiguration constraintValidatorFactory(final
402             ConstraintValidatorFactory factory) {
403             return this;
404         }
405 
406         @Override
407         public FakeConfiguration parameterNameProvider(final ParameterNameProvider provider) {
408             return this;
409         }
410 
411         @Override
412         public FakeConfiguration clockProvider(final ClockProvider provider) {
413             return this;
414         }
415 
416         @Override
417         public FakeConfiguration addValueExtractor(final ValueExtractor<?> extractor) {
418             return this;
419         }
420 
421         @Override
422         public FakeConfiguration addMapping(final InputStream stream) {
423             return this;
424         }
425 
426         @Override
427         public FakeConfiguration addProperty(final String str, final String another) {
428             return this;
429         }
430 
431         @Override
432         public MessageInterpolator getDefaultMessageInterpolator() {
433             return null;
434         }
435 
436         @Override
437         public TraversableResolver getDefaultTraversableResolver() {
438             return null;
439         }
440 
441         @Override
442         public ConstraintValidatorFactory getDefaultConstraintValidatorFactory() {
443             return null;
444         }
445 
446         @Override
447         public ParameterNameProvider getDefaultParameterNameProvider() {
448             return null;
449         }
450 
451         @Override
452         public ClockProvider getDefaultClockProvider() {
453             return null;
454         }
455 
456         @Override
457         public BootstrapConfiguration getBootstrapConfiguration() {
458             return null;
459         }
460 
461         @Override
462         public ValidatorFactory buildValidatorFactory() {
463             return new FakeValidatorFactory();
464         }
465     }
466 }