From 3ec4fa3dee2fa6c55492594aaeed0b083ee32cba Mon Sep 17 00:00:00 2001 From: Michael Schnell Date: Sun, 14 Jan 2024 10:25:52 +0100 Subject: [PATCH] Added new static method annotations --- ...java => HasPublicStaticIsValidMethod.java} | 14 +- ...HasPublicStaticIsValidMethodValidator.java | 61 +++++++++ .../common/HasPublicStaticIsValidMethods.java | 21 +++ ...java => HasPublicStaticValueOfMethod.java} | 14 +- ...HasPublicStaticValueOfMethodValidator.java | 61 +++++++++ ...ava => HasPublicStaticValueOfMethods.java} | 6 +- .../objects4j/common/IsValidCapables.java | 21 --- .../objects4j/vo/AbstractUuidValueObject.java | 3 + .../org/fuin/objects4j/vo/DayOfTheWeek.java | 9 +- .../fuin/objects4j/vo/DayOpeningHours.java | 8 +- src/main/java/org/fuin/objects4j/vo/Hour.java | 8 +- .../java/org/fuin/objects4j/vo/HourRange.java | 8 +- .../org/fuin/objects4j/vo/HourRanges.java | 9 +- .../fuin/objects4j/vo/MultiDayOfTheWeek.java | 8 +- .../fuin/objects4j/vo/WeeklyOpeningHours.java | 8 +- ...ublicStaticIsValidMethodValidatorTest.java | 127 +++++++++++++++++ ...ublicStaticValueOfMethodValidatorTest.java | 129 ++++++++++++++++++ 17 files changed, 459 insertions(+), 56 deletions(-) rename src/main/java/org/fuin/objects4j/common/{IsValidCapable.java => HasPublicStaticIsValidMethod.java} (70%) create mode 100644 src/main/java/org/fuin/objects4j/common/HasPublicStaticIsValidMethodValidator.java create mode 100644 src/main/java/org/fuin/objects4j/common/HasPublicStaticIsValidMethods.java rename src/main/java/org/fuin/objects4j/common/{ValueOfCapable.java => HasPublicStaticValueOfMethod.java} (70%) create mode 100644 src/main/java/org/fuin/objects4j/common/HasPublicStaticValueOfMethodValidator.java rename src/main/java/org/fuin/objects4j/common/{ValueOfCapables.java => HasPublicStaticValueOfMethods.java} (62%) delete mode 100644 src/main/java/org/fuin/objects4j/common/IsValidCapables.java create mode 100644 src/test/java/org/fuin/objects4j/common/HasPublicStaticIsValidMethodValidatorTest.java create mode 100644 src/test/java/org/fuin/objects4j/common/HasPublicStaticValueOfMethodValidatorTest.java diff --git a/src/main/java/org/fuin/objects4j/common/IsValidCapable.java b/src/main/java/org/fuin/objects4j/common/HasPublicStaticIsValidMethod.java similarity index 70% rename from src/main/java/org/fuin/objects4j/common/IsValidCapable.java rename to src/main/java/org/fuin/objects4j/common/HasPublicStaticIsValidMethod.java index f56cdc1..ff00fec 100644 --- a/src/main/java/org/fuin/objects4j/common/IsValidCapable.java +++ b/src/main/java/org/fuin/objects4j/common/HasPublicStaticIsValidMethod.java @@ -1,5 +1,8 @@ package org.fuin.objects4j.common; +import jakarta.validation.Constraint; +import jakarta.validation.Payload; + import java.lang.annotation.*; /** @@ -10,8 +13,9 @@ @Target(ElementType.TYPE) @Inherited @Retention(RetentionPolicy.RUNTIME) -@Repeatable(IsValidCapables.class) -public @interface IsValidCapable { +@Repeatable(HasPublicStaticIsValidMethods.class) +@Constraint(validatedBy = { HasPublicStaticIsValidMethodValidator.class }) +public @interface HasPublicStaticIsValidMethod { /** * Returns the name of a public static method in the annotated class.
@@ -34,4 +38,10 @@ */ Class param() default String.class; + String message() default "Does not define a public static method with the given argument type and returns boolean"; + + Class[] groups() default {}; + + Class[] payload() default {}; + } diff --git a/src/main/java/org/fuin/objects4j/common/HasPublicStaticIsValidMethodValidator.java b/src/main/java/org/fuin/objects4j/common/HasPublicStaticIsValidMethodValidator.java new file mode 100644 index 0000000..d674e7f --- /dev/null +++ b/src/main/java/org/fuin/objects4j/common/HasPublicStaticIsValidMethodValidator.java @@ -0,0 +1,61 @@ +package org.fuin.objects4j.common; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +/** + * Determines if the annotated class has: + * - a public static method with the given name + * - a parameter with the given type + * defined in the annotation and the return type of that method is {@literal boolean}. + */ +public class HasPublicStaticIsValidMethodValidator implements ConstraintValidator { + + private String methodName; + + private Class paramClass; + + @Override + public void initialize(HasPublicStaticIsValidMethod annotation) { + this.methodName = annotation.method(); + this.paramClass = annotation.param(); + } + + @Override + public boolean isValid(Object obj, ConstraintValidatorContext context) { + try { + final Method method = obj.getClass().getMethod(methodName, paramClass); + final int modifiers = method.getModifiers(); + if (!Modifier.isStatic(modifiers)) { + error(context, "Method '" + methodName + "' is not static (#1)"); + return false; + } + if (method.getReturnType() != boolean.class) { + error(context, "Method '" + methodName + "' does not return 'boolean', but: " + method.getReturnType().getName() + " (#3)"); + return false; + } + final boolean valid = (boolean) method.invoke(obj, (Object) null); + if (!valid) { + error(context, "Method '" + methodName + "' is expected to return 'true' on 'null' argument, but was 'false' (#4)"); + return false; + } + return true; + } catch (final NoSuchMethodException ex) { + error(context, "The method '" + methodName + "' is undefined or it is not public (#2)"); + return false; + } catch (final IllegalAccessException | InvocationTargetException ex) { + throw new IllegalStateException("Failed to execute method", ex); + } + + } + + private void error(ConstraintValidatorContext context, String message) { + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate(message).addConstraintViolation(); + } + +} diff --git a/src/main/java/org/fuin/objects4j/common/HasPublicStaticIsValidMethods.java b/src/main/java/org/fuin/objects4j/common/HasPublicStaticIsValidMethods.java new file mode 100644 index 0000000..90034d5 --- /dev/null +++ b/src/main/java/org/fuin/objects4j/common/HasPublicStaticIsValidMethods.java @@ -0,0 +1,21 @@ +package org.fuin.objects4j.common; + +import java.lang.annotation.*; + +/** + * Collection of {@link HasPublicStaticIsValidMethod} annotations. + */ +@Documented +@Target(ElementType.TYPE) +@Inherited +@Retention(RetentionPolicy.RUNTIME) +public @interface HasPublicStaticIsValidMethods { + + /** + * Returns a list of {@link HasPublicStaticIsValidMethod} instances. + * + * @return Array of annotations. + */ + HasPublicStaticIsValidMethod[] value(); + +} diff --git a/src/main/java/org/fuin/objects4j/common/ValueOfCapable.java b/src/main/java/org/fuin/objects4j/common/HasPublicStaticValueOfMethod.java similarity index 70% rename from src/main/java/org/fuin/objects4j/common/ValueOfCapable.java rename to src/main/java/org/fuin/objects4j/common/HasPublicStaticValueOfMethod.java index 051b694..00097ee 100644 --- a/src/main/java/org/fuin/objects4j/common/ValueOfCapable.java +++ b/src/main/java/org/fuin/objects4j/common/HasPublicStaticValueOfMethod.java @@ -1,5 +1,8 @@ package org.fuin.objects4j.common; +import jakarta.validation.Constraint; +import jakarta.validation.Payload; + import java.lang.annotation.*; /** @@ -10,8 +13,9 @@ @Target(ElementType.TYPE) @Inherited @Retention(RetentionPolicy.RUNTIME) -@Repeatable(ValueOfCapables.class) -public @interface ValueOfCapable { +@Repeatable(HasPublicStaticValueOfMethods.class) +@Constraint(validatedBy = { HasPublicStaticValueOfMethodValidator.class }) +public @interface HasPublicStaticValueOfMethod { /** * Returns the name of a public static method in the annotated class.
@@ -34,4 +38,10 @@ */ Class param() default String.class; + String message() default "Does not define a public static method with the given argument type and returns boolean"; + + Class[] groups() default {}; + + Class[] payload() default {}; + } diff --git a/src/main/java/org/fuin/objects4j/common/HasPublicStaticValueOfMethodValidator.java b/src/main/java/org/fuin/objects4j/common/HasPublicStaticValueOfMethodValidator.java new file mode 100644 index 0000000..6610c26 --- /dev/null +++ b/src/main/java/org/fuin/objects4j/common/HasPublicStaticValueOfMethodValidator.java @@ -0,0 +1,61 @@ +package org.fuin.objects4j.common; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +/** + * Determines if the annotated class has: + * - a public static method with the given name + * - a parameter with the given type + * defined in the annotation and the return type of that method is the same as the annotated class. + */ +public class HasPublicStaticValueOfMethodValidator implements ConstraintValidator { + + private String methodName; + + private Class paramClass; + + @Override + public void initialize(HasPublicStaticValueOfMethod annotation) { + this.methodName = annotation.method(); + this.paramClass = annotation.param(); + } + + @Override + public boolean isValid(Object obj, ConstraintValidatorContext context) { + try { + final Method method = obj.getClass().getMethod(methodName, paramClass); + final int modifiers = method.getModifiers(); + if (!Modifier.isStatic(modifiers)) { + error(context, "Method '" + methodName + "' is not static (#1)"); + return false; + } + if (method.getReturnType() != obj.getClass()) { + error(context, "Method '" + methodName + "' does not return '" + obj.getClass().getName() + "', but: " + method.getReturnType().getName() + " (#3)"); + return false; + } + final Object value = method.invoke(obj, (Object) null); + if (value != null) { + error(context, "Method '" + methodName + "' is expected to return 'true' on 'null' argument, but was: " + value + " (#4)"); + return false; + } + return true; + } catch (final NoSuchMethodException ex) { + error(context, "The method '" + methodName + "' is undefined or it is not public (#2)"); + return false; + } catch (final IllegalAccessException | InvocationTargetException ex) { + throw new IllegalStateException("Failed to execute method", ex); + } + + } + + private void error(ConstraintValidatorContext context, String message) { + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate(message).addConstraintViolation(); + } + +} diff --git a/src/main/java/org/fuin/objects4j/common/ValueOfCapables.java b/src/main/java/org/fuin/objects4j/common/HasPublicStaticValueOfMethods.java similarity index 62% rename from src/main/java/org/fuin/objects4j/common/ValueOfCapables.java rename to src/main/java/org/fuin/objects4j/common/HasPublicStaticValueOfMethods.java index b8fb536..8a1a930 100644 --- a/src/main/java/org/fuin/objects4j/common/ValueOfCapables.java +++ b/src/main/java/org/fuin/objects4j/common/HasPublicStaticValueOfMethods.java @@ -3,19 +3,19 @@ import java.lang.annotation.*; /** - * Collection of {@link ValueOfCapable} annotations. + * Collection of {@link HasPublicStaticValueOfMethod} annotations. */ @Documented @Target(ElementType.TYPE) @Inherited @Retention(RetentionPolicy.RUNTIME) -public @interface ValueOfCapables { +public @interface HasPublicStaticValueOfMethods { /** * Returns a list of annotations. * * @return Array of annotations. */ - ValueOfCapable[] value(); + HasPublicStaticValueOfMethod[] value(); } diff --git a/src/main/java/org/fuin/objects4j/common/IsValidCapables.java b/src/main/java/org/fuin/objects4j/common/IsValidCapables.java deleted file mode 100644 index 71b1c06..0000000 --- a/src/main/java/org/fuin/objects4j/common/IsValidCapables.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.fuin.objects4j.common; - -import java.lang.annotation.*; - -/** - * Collection of {@link IsValidCapable} annotations. - */ -@Documented -@Target(ElementType.TYPE) -@Inherited -@Retention(RetentionPolicy.RUNTIME) -public @interface IsValidCapables { - - /** - * Returns a list of {@link IsValidCapable} instances. - * - * @return Array of annotations. - */ - IsValidCapable[] value(); - -} diff --git a/src/main/java/org/fuin/objects4j/vo/AbstractUuidValueObject.java b/src/main/java/org/fuin/objects4j/vo/AbstractUuidValueObject.java index 71a17f2..9d4d142 100644 --- a/src/main/java/org/fuin/objects4j/vo/AbstractUuidValueObject.java +++ b/src/main/java/org/fuin/objects4j/vo/AbstractUuidValueObject.java @@ -17,6 +17,8 @@ */ package org.fuin.objects4j.vo; +import org.fuin.objects4j.common.HasPublicStaticIsValidMethod; + import java.io.Serializable; import java.util.UUID; import java.util.regex.Pattern; @@ -25,6 +27,7 @@ * Base class for UUID value objects that that overrides {@link Object#hashCode()} and {@link Object#equals(Object)} and it implements * comparable based on the {@link #asBaseType()} method. */ +@HasPublicStaticIsValidMethod public abstract class AbstractUuidValueObject implements ValueObjectWithBaseType, Comparable, Serializable { private static final long serialVersionUID = 1000L; diff --git a/src/main/java/org/fuin/objects4j/vo/DayOfTheWeek.java b/src/main/java/org/fuin/objects4j/vo/DayOfTheWeek.java index 04727e7..8451f6b 100644 --- a/src/main/java/org/fuin/objects4j/vo/DayOfTheWeek.java +++ b/src/main/java/org/fuin/objects4j/vo/DayOfTheWeek.java @@ -20,10 +20,8 @@ import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter; -import org.fuin.objects4j.common.ConstraintViolationException; -import org.fuin.objects4j.common.Contract; -import org.fuin.objects4j.common.Immutable; -import org.fuin.objects4j.common.Nullable; +import org.fuin.objects4j.common.*; +import org.fuin.objects4j.common.HasPublicStaticValueOfMethod; import org.fuin.objects4j.ui.Label; import org.fuin.objects4j.ui.Prompt; import org.fuin.objects4j.ui.ShortLabel; @@ -44,6 +42,9 @@ @Tooltip("The days of the week 'Mon'-'Sun'(from Monday to Sunday) plus 'PH' (Public Holiday)") @Prompt("Fri") @XmlJavaTypeAdapter(DayOfTheWeekConverter.class) +@HasPublicStaticIsValidMethod +@HasPublicStaticValueOfMethod(method = "valueOf", param = String.class) +@HasPublicStaticValueOfMethod(method = "valueOf", param = DayOfWeek.class) public final class DayOfTheWeek implements ValueObjectWithBaseType, Comparable, Serializable, AsStringCapable { private static final long serialVersionUID = 1000L; diff --git a/src/main/java/org/fuin/objects4j/vo/DayOpeningHours.java b/src/main/java/org/fuin/objects4j/vo/DayOpeningHours.java index 09970df..a97652a 100644 --- a/src/main/java/org/fuin/objects4j/vo/DayOpeningHours.java +++ b/src/main/java/org/fuin/objects4j/vo/DayOpeningHours.java @@ -20,10 +20,8 @@ import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter; -import org.fuin.objects4j.common.ConstraintViolationException; -import org.fuin.objects4j.common.Contract; -import org.fuin.objects4j.common.Immutable; -import org.fuin.objects4j.common.Nullable; +import org.fuin.objects4j.common.*; +import org.fuin.objects4j.common.HasPublicStaticValueOfMethod; import org.fuin.objects4j.ui.Prompt; import org.fuin.objects4j.vo.HourRanges.ChangeType; @@ -44,6 +42,8 @@ @Immutable @Prompt("Mon 09:00-12:00+13:00-17:00") @XmlJavaTypeAdapter(DayOpeningHoursConverter.class) +@HasPublicStaticIsValidMethod +@HasPublicStaticValueOfMethod public final class DayOpeningHours implements ValueObjectWithBaseType, Comparable, Serializable, AsStringCapable { private static final long serialVersionUID = 1000L; diff --git a/src/main/java/org/fuin/objects4j/vo/Hour.java b/src/main/java/org/fuin/objects4j/vo/Hour.java index 7670632..c090abf 100644 --- a/src/main/java/org/fuin/objects4j/vo/Hour.java +++ b/src/main/java/org/fuin/objects4j/vo/Hour.java @@ -20,10 +20,8 @@ import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter; -import org.fuin.objects4j.common.ConstraintViolationException; -import org.fuin.objects4j.common.Contract; -import org.fuin.objects4j.common.Immutable; -import org.fuin.objects4j.common.Nullable; +import org.fuin.objects4j.common.*; +import org.fuin.objects4j.common.HasPublicStaticValueOfMethod; import org.fuin.objects4j.ui.Label; import org.fuin.objects4j.ui.Prompt; import org.fuin.objects4j.ui.ShortLabel; @@ -51,6 +49,8 @@ @Tooltip("Hour of a day") @Prompt("23:59") @XmlJavaTypeAdapter(HourConverter.class) +@HasPublicStaticIsValidMethod +@HasPublicStaticValueOfMethod public final class Hour extends AbstractStringValueObject { private static final long serialVersionUID = 1000L; diff --git a/src/main/java/org/fuin/objects4j/vo/HourRange.java b/src/main/java/org/fuin/objects4j/vo/HourRange.java index a75fd6c..c6cf836 100644 --- a/src/main/java/org/fuin/objects4j/vo/HourRange.java +++ b/src/main/java/org/fuin/objects4j/vo/HourRange.java @@ -20,10 +20,8 @@ import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter; -import org.fuin.objects4j.common.ConstraintViolationException; -import org.fuin.objects4j.common.Contract; -import org.fuin.objects4j.common.Immutable; -import org.fuin.objects4j.common.Nullable; +import org.fuin.objects4j.common.*; +import org.fuin.objects4j.common.HasPublicStaticValueOfMethod; import org.fuin.objects4j.ui.Label; import org.fuin.objects4j.ui.Prompt; import org.fuin.objects4j.ui.ShortLabel; @@ -51,6 +49,8 @@ @Tooltip("From hourRange of day until hourRange of day") @Prompt("00:00-24:00") @XmlJavaTypeAdapter(HourRangeConverter.class) +@HasPublicStaticIsValidMethod +@HasPublicStaticValueOfMethod public final class HourRange extends AbstractStringValueObject { private static final long serialVersionUID = 1000L; diff --git a/src/main/java/org/fuin/objects4j/vo/HourRanges.java b/src/main/java/org/fuin/objects4j/vo/HourRanges.java index d565387..51dbbaf 100644 --- a/src/main/java/org/fuin/objects4j/vo/HourRanges.java +++ b/src/main/java/org/fuin/objects4j/vo/HourRanges.java @@ -20,10 +20,8 @@ import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter; -import org.fuin.objects4j.common.ConstraintViolationException; -import org.fuin.objects4j.common.Contract; -import org.fuin.objects4j.common.Immutable; -import org.fuin.objects4j.common.Nullable; +import org.fuin.objects4j.common.*; +import org.fuin.objects4j.common.HasPublicStaticValueOfMethod; import org.fuin.objects4j.ui.Prompt; import java.util.*; @@ -35,6 +33,9 @@ @Immutable @Prompt("09:00-12:00+13:00-17:00") @XmlJavaTypeAdapter(HourRangesConverter.class) +@HasPublicStaticIsValidMethod +@HasPublicStaticValueOfMethod(method = "valueOf", param = String.class) +@HasPublicStaticValueOfMethod(method = "valueOf", param = BitSet.class) public final class HourRanges extends AbstractStringValueObject implements Iterable { private static final long serialVersionUID = 1000L; diff --git a/src/main/java/org/fuin/objects4j/vo/MultiDayOfTheWeek.java b/src/main/java/org/fuin/objects4j/vo/MultiDayOfTheWeek.java index a0d6f12..88d21fb 100644 --- a/src/main/java/org/fuin/objects4j/vo/MultiDayOfTheWeek.java +++ b/src/main/java/org/fuin/objects4j/vo/MultiDayOfTheWeek.java @@ -20,10 +20,8 @@ import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter; -import org.fuin.objects4j.common.ConstraintViolationException; -import org.fuin.objects4j.common.Contract; -import org.fuin.objects4j.common.Immutable; -import org.fuin.objects4j.common.Nullable; +import org.fuin.objects4j.common.*; +import org.fuin.objects4j.common.HasPublicStaticValueOfMethod; import org.fuin.objects4j.ui.Prompt; import java.util.*; @@ -41,6 +39,8 @@ @Immutable @Prompt("Mon/Tue/Wed-Fri") @XmlJavaTypeAdapter(MultiDayOfTheWeekConverter.class) +@HasPublicStaticIsValidMethod +@HasPublicStaticValueOfMethod public final class MultiDayOfTheWeek extends AbstractStringValueObject implements Iterable { private static final long serialVersionUID = 1000L; diff --git a/src/main/java/org/fuin/objects4j/vo/WeeklyOpeningHours.java b/src/main/java/org/fuin/objects4j/vo/WeeklyOpeningHours.java index b560664..048ad28 100644 --- a/src/main/java/org/fuin/objects4j/vo/WeeklyOpeningHours.java +++ b/src/main/java/org/fuin/objects4j/vo/WeeklyOpeningHours.java @@ -20,10 +20,8 @@ import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter; -import org.fuin.objects4j.common.ConstraintViolationException; -import org.fuin.objects4j.common.Contract; -import org.fuin.objects4j.common.Immutable; -import org.fuin.objects4j.common.Nullable; +import org.fuin.objects4j.common.*; +import org.fuin.objects4j.common.HasPublicStaticValueOfMethod; import org.fuin.objects4j.ui.Prompt; import org.fuin.objects4j.vo.DayOpeningHours.Change; @@ -37,6 +35,8 @@ @Immutable @Prompt("Mon-Fri 09:00-12:00+13:00-17:00,Sat/Sun 09:-12:00") @XmlJavaTypeAdapter(WeeklyOpeningHoursConverter.class) +@HasPublicStaticIsValidMethod +@HasPublicStaticValueOfMethod public final class WeeklyOpeningHours extends AbstractStringValueObject implements Iterable { private static final long serialVersionUID = 1000L; diff --git a/src/test/java/org/fuin/objects4j/common/HasPublicStaticIsValidMethodValidatorTest.java b/src/test/java/org/fuin/objects4j/common/HasPublicStaticIsValidMethodValidatorTest.java new file mode 100644 index 0000000..d49d16a --- /dev/null +++ b/src/test/java/org/fuin/objects4j/common/HasPublicStaticIsValidMethodValidatorTest.java @@ -0,0 +1,127 @@ +/** + * Copyright (C) 2013 Future Invent Informationsmanagement GmbH. All rights + * reserved. + *

+ * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) any + * later version. + *

+ * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + *

+ * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +package org.fuin.objects4j.common; + +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import jakarta.validation.ValidatorFactory; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +public final class HasPublicStaticIsValidMethodValidatorTest { + + private static Validator validator; + + @BeforeAll + static void beforeAll() { + try (final ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory()) { + validator = validatorFactory.getValidator(); + } + } + + @Test + public final void testValid() { + assertThat(validator.validate(new MyClassValid())).isEmpty(); + } + + @Test + public final void testNotStatic() { + assertThat(first(validator.validate(new MyClassNotStatic()))).contains("#1"); + } + + @Test + public final void testNotPublic() { + assertThat(first(validator.validate(new MyClassNotPublic()))).contains("#2"); + } + + @Test + public final void testWrongReturnType() { + assertThat(first(validator.validate(new MyClassWrongReturnType()))).contains("#3"); + } + + @Test + public final void testWrongReturn() { + assertThat(first(validator.validate(new MyClassWrongReturnValue()))).contains("#4"); + } + + @Test + public final void testNoMethod() { + assertThat(first(validator.validate(new MyClassNoMethod()))).contains("#2"); + } + + private static String first(Set violations) { + return violations.stream().map(v -> ((ConstraintViolation) v).getMessage()).findFirst().orElse(null); + } + + @HasPublicStaticIsValidMethod + public static final class MyClassValid { + public static boolean isValid(String str) { + if (str == null) { + return true; + } + return true; + } + } + + @HasPublicStaticIsValidMethod + public static final class MyClassNotStatic { + public boolean isValid(String str) { + return true; + } + } + + @HasPublicStaticIsValidMethod + public static final class MyClassNotPublic { + protected static boolean isValid(String str) { + if (str == null) { + return true; + } + return true; + } + } + + @HasPublicStaticIsValidMethod + public static final class MyClassNoMethod { + } + + @HasPublicStaticIsValidMethod + public static final class MyClassWrongReturnType { + public static Boolean isValid(String str) { + if (str == null) { + return false; + } + return true; + } + } + @HasPublicStaticIsValidMethod + public static final class MyClassWrongReturnValue { + public static boolean isValid(String str) { + if (str == null) { + return false; + } + return true; + } + } + + +} diff --git a/src/test/java/org/fuin/objects4j/common/HasPublicStaticValueOfMethodValidatorTest.java b/src/test/java/org/fuin/objects4j/common/HasPublicStaticValueOfMethodValidatorTest.java new file mode 100644 index 0000000..6432575 --- /dev/null +++ b/src/test/java/org/fuin/objects4j/common/HasPublicStaticValueOfMethodValidatorTest.java @@ -0,0 +1,129 @@ +/** + * Copyright (C) 2013 Future Invent Informationsmanagement GmbH. All rights + * reserved. + *

+ * This library is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) any + * later version. + *

+ * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + *

+ * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ +package org.fuin.objects4j.common; + +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import jakarta.validation.ValidatorFactory; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +public final class HasPublicStaticValueOfMethodValidatorTest { + + private static Validator validator; + + @BeforeAll + static void beforeAll() { + try (final ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory()) { + validator = validatorFactory.getValidator(); + } + } + + @Test + public final void testValid() { + assertThat(validator.validate(new MyClassValid())).isEmpty(); + } + + @Test + public final void testNotStatic() { + assertThat(first(validator.validate(new MyClassNotStatic()))).contains("#1"); + } + + @Test + public final void testNotPublic() { + assertThat(first(validator.validate(new MyClassNotPublic()))).contains("#2"); + } + + @Test + public final void testWrongReturnType() { + assertThat(first(validator.validate(new MyClassWrongReturnType()))).contains("#3"); + } + + @Test + public final void testWrongReturn() { + assertThat(first(validator.validate(new MyClassWrongReturnValue()))).contains("#4"); + } + + @Test + public final void testNoMethod() { + assertThat(first(validator.validate(new MyClassNoMethod()))).contains("#2"); + } + + private static String first(Set violations) { + return violations.stream().map(v -> ((ConstraintViolation) v).getMessage()).findFirst().orElse(null); + } + + @HasPublicStaticValueOfMethod + public static final class MyClassValid { + public static MyClassValid valueOf(String str) { + if (str == null) { + return null; + } + return new MyClassValid(); + } + } + + @HasPublicStaticValueOfMethod + public static final class MyClassNotStatic { + public MyClassNotStatic valueOf(String str) { + if (str == null) { + return null; + } + return new MyClassNotStatic(); + } + } + + @HasPublicStaticValueOfMethod + public static final class MyClassNotPublic { + protected static MyClassNotPublic valueOf(String str) { + if (str == null) { + return null; + } + return new MyClassNotPublic(); + } + } + + @HasPublicStaticValueOfMethod + public static final class MyClassNoMethod { + } + + @HasPublicStaticValueOfMethod + public static final class MyClassWrongReturnType { + public static Integer valueOf(String str) { + if (str == null) { + return null; + } + return 0; + } + } + + @HasPublicStaticValueOfMethod + public static final class MyClassWrongReturnValue { + public static MyClassWrongReturnValue valueOf(String str) { + return new MyClassWrongReturnValue(); + } + } + + +}