From bdb634385a655f03c8513ff80149895789c124bf Mon Sep 17 00:00:00 2001 From: hduelme Date: Mon, 16 Mar 2026 01:10:33 +0100 Subject: [PATCH 1/2] Support getting a value or invoking a supplier if the value is not set --- .../main/java/org/mapstruct/tools/gem/GemValue.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/api/src/main/java/org/mapstruct/tools/gem/GemValue.java b/api/src/main/java/org/mapstruct/tools/gem/GemValue.java index 65f86df..e8b4a5b 100644 --- a/api/src/main/java/org/mapstruct/tools/gem/GemValue.java +++ b/api/src/main/java/org/mapstruct/tools/gem/GemValue.java @@ -8,6 +8,7 @@ import java.util.ArrayList; import java.util.List; import java.util.function.Function; +import java.util.function.Supplier; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.AnnotationValueVisitor; @@ -113,6 +114,16 @@ public T getValue() { return value; } + /** + * Returns the value set by the user, if present, otherwise invoke other and return the result of that invocation. + * + * @param other a Supplier whose result is returned if no value is present + * @return the value set by the user, if present, otherwise the result of {@code other.get()} + */ + public T getValueOrElseGet(Supplier other) { + return value != null ? value : other.get(); + } + /** * The default value, as declared in the annotation * From 91df7853bdf604ebff45e0ec6bc2ecc10a913ac2 Mon Sep 17 00:00:00 2001 From: hduelme Date: Mon, 16 Mar 2026 14:33:32 +0100 Subject: [PATCH 2/2] added test for public api --- api/pom.xml | 17 ++ .../org/mapstruct/tools/gem/GemValueTest.java | 195 ++++++++++++++++++ 2 files changed, 212 insertions(+) create mode 100644 api/src/test/java/org/mapstruct/tools/gem/GemValueTest.java diff --git a/api/pom.xml b/api/pom.xml index 0e1500a..c586b35 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -20,6 +20,19 @@ jar MapStruct Tools Gem API + + + org.junit.jupiter + junit-jupiter + test + + + org.assertj + assertj-core + test + + + @@ -71,6 +84,10 @@ + + org.apache.maven.plugins + maven-surefire-plugin + org.apache.felix maven-bundle-plugin diff --git a/api/src/test/java/org/mapstruct/tools/gem/GemValueTest.java b/api/src/test/java/org/mapstruct/tools/gem/GemValueTest.java new file mode 100644 index 0000000..b366cde --- /dev/null +++ b/api/src/test/java/org/mapstruct/tools/gem/GemValueTest.java @@ -0,0 +1,195 @@ +/* + * Copyright MapStruct Authors. + * + * Licensed under the Apache License version 2.0, available at https://www.apache.org/licenses/LICENSE-2.0 + */ +package org.mapstruct.tools.gem; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import javax.lang.model.element.AnnotationValue; +import javax.lang.model.element.AnnotationValueVisitor; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class GemValueTest { + + static class SimpleAnnotationValue implements AnnotationValue { + + private final int value; + + SimpleAnnotationValue(int value) { + this.value = value; + } + + @Override + public Object getValue() { + return value; + } + + @Override + public R accept(AnnotationValueVisitor v, P p) { + return v.visitInt( value, p ); + } + } + + @Nested + class CreateSimpleValueTest { + + @Test + void createSimpleValue() { + SimpleAnnotationValue annotationValue = new SimpleAnnotationValue(1); + GemValue gemValue = GemValue.create( annotationValue, new SimpleAnnotationValue(2), + Integer.class ); + assertThat( gemValue ).isNotNull(); + assertThat( gemValue.isValid() ).isTrue(); + assertThat( gemValue.hasValue() ).isTrue(); + assertThat( gemValue.getValue() ).isEqualTo( 1 ); + assertThat( gemValue.getDefaultValue() ).isEqualTo( 2 ); + assertThat( gemValue.get() ).as( "get should return value" ).isEqualTo( 1 ); + assertThat( gemValue.getAnnotationValue() ).isEqualTo( annotationValue ); + assertThat( gemValue.getValueOrElseGet( () -> 3 ) ) + .as( "getValueOrElseGet should return value" ).isEqualTo( 1 ); + } + + @Test + void createSimpleValueWithoutAnnotationValue() { + GemValue gemValue = GemValue.create( null, new SimpleAnnotationValue(2), + Integer.class ); + assertThat( gemValue ).isNotNull(); + assertThat( gemValue.isValid() ).isTrue(); + assertThat( gemValue.hasValue() ).isFalse(); + assertThat( gemValue.getValue() ).isNull(); + assertThat( gemValue.getDefaultValue() ).isEqualTo( 2 ); + assertThat( gemValue.get() ).as( "get should return defaultValue" ).isEqualTo( 2 ); + assertThat( gemValue.getAnnotationValue() ).isNull(); + assertThat( gemValue.getValueOrElseGet( () -> 3 ) ) + .as( "getValueOrElseGet should return other" ).isEqualTo( 3 ); + } + + @Test + void createSimpleValueWithoutAnnotationDefaultValue() { + SimpleAnnotationValue annotationValue = new SimpleAnnotationValue(1); + GemValue gemValue = GemValue.create( annotationValue, null, Integer.class ); + assertThat( gemValue ).isNotNull(); + assertThat( gemValue.isValid() ).isTrue(); + assertThat( gemValue.hasValue() ).isTrue(); + assertThat( gemValue.getValue() ).isEqualTo( 1 ); + assertThat( gemValue.getDefaultValue() ).isNull(); + assertThat( gemValue.get() ).as( "get should return value" ).isEqualTo( 1 ); + assertThat( gemValue.getAnnotationValue() ).isEqualTo( annotationValue ); + assertThat( gemValue.getValueOrElseGet( () -> 3 ) ) + .as( "getValueOrElseGet should return value" ).isEqualTo( 1 ); + } + + @Test + void createSimpleValueInvalid() { + GemValue gemValue = GemValue.create( null, null, Integer.class ); + assertThat( gemValue ).isNotNull(); + assertThat( gemValue.isValid() ).isFalse(); + assertThat( gemValue.hasValue() ).isFalse(); + assertThat( gemValue.getValue() ).isNull(); + assertThat( gemValue.getDefaultValue() ).isNull(); + assertThat( gemValue.get() ).as( "get should return null" ).isNull(); + assertThat( gemValue.getAnnotationValue() ).isNull(); + assertThat( gemValue.getValueOrElseGet( () -> 3 ) ) + .as( "getValueOrElseGet should return other" ).isEqualTo( 3 ); + } + } + + static class SimpleArrayAnnotationValue implements AnnotationValue { + + private final List value; + + SimpleArrayAnnotationValue(int... intValues) { + this.value = new ArrayList<>( intValues.length ); + for ( int v : intValues ) { + value.add( new SimpleAnnotationValue( v ) ); + } + } + + @Override + public Object getValue() { + return value; + } + + @Override + public R accept(AnnotationValueVisitor v, P p) { + return v.visitArray( value, p ); + } + } + + @Nested + class CreateArrayTest { + + @Test + void createArrayValue() { + SimpleArrayAnnotationValue annotationValue = new SimpleArrayAnnotationValue(1); + GemValue> gemValue = GemValue.createArray( annotationValue, + new SimpleArrayAnnotationValue(2), Integer.class ); + assertThat( gemValue ).isNotNull(); + assertThat( gemValue.isValid() ).isTrue(); + assertThat( gemValue.hasValue() ).isTrue(); + assertThat( gemValue.getValue() ).isEqualTo( Collections.singletonList( 1 ) ); + assertThat( gemValue.getDefaultValue() ).isEqualTo( Collections.singletonList( 2 ) ); + assertThat( gemValue.get() ).as( "get should return value" ).isEqualTo( + Collections.singletonList( 1 ) ); + assertThat( gemValue.getAnnotationValue() ).isEqualTo( annotationValue ); + assertThat( gemValue.getValueOrElseGet( Collections::emptyList ) ) + .as( "getValueOrElseGet should return value" ) + .isEqualTo( Collections.singletonList( 1 ) ); + } + + @Test + void createArrayValueWithoutAnnotationValue() { + GemValue> gemValue = GemValue.createArray( null, + new SimpleArrayAnnotationValue(2), Integer.class ); + assertThat( gemValue ).isNotNull(); + assertThat( gemValue.isValid() ).isTrue(); + assertThat( gemValue.hasValue() ).isFalse(); + assertThat( gemValue.getValue() ).isNull(); + assertThat( gemValue.getDefaultValue() ).isEqualTo( Collections.singletonList( 2 ) ); + assertThat( gemValue.get() ).as( "get should return defaultValue" ) + .isEqualTo( Collections.singletonList( 2 ) ); + assertThat( gemValue.getAnnotationValue() ).isNull(); + assertThat( gemValue.getValueOrElseGet( Collections::emptyList ) ) + .as( "getValueOrElseGet should return other" ).isEqualTo( Collections.emptyList() ); + } + + @Test + void createArrayValueWithoutAnnotationDefaultValue() { + SimpleArrayAnnotationValue annotationValue = new SimpleArrayAnnotationValue(1); + GemValue> gemValue = GemValue.createArray( annotationValue, null, Integer.class ); + assertThat( gemValue ).isNotNull(); + assertThat( gemValue.isValid() ).isTrue(); + assertThat( gemValue.hasValue() ).isTrue(); + assertThat( gemValue.getValue() ).isEqualTo( Collections.singletonList( 1 ) ); + assertThat( gemValue.getDefaultValue() ).isNull(); + assertThat( gemValue.get() ).as( "get should return value" ) + .isEqualTo( Collections.singletonList( 1 ) ); + assertThat( gemValue.getAnnotationValue() ).isEqualTo( annotationValue ); + assertThat( gemValue.getValueOrElseGet( Collections::emptyList ) ) + .as( "getValueOrElseGet should return value" ) + .isEqualTo( Collections.singletonList( 1 ) ); + } + + @Test + void createArrayValueInvalid() { + GemValue> gemValue = GemValue.createArray( null, null, Integer.class ); + assertThat( gemValue ).isNotNull(); + assertThat( gemValue.isValid() ).isFalse(); + assertThat( gemValue.hasValue() ).isFalse(); + assertThat( gemValue.getValue() ).isNull(); + assertThat( gemValue.getDefaultValue() ).isNull(); + assertThat( gemValue.get() ).as( "get should return null" ).isNull(); + assertThat( gemValue.getAnnotationValue() ).isNull(); + assertThat( gemValue.getValueOrElseGet( () -> Collections.singletonList( 3 ) ) ) + .as( "getValueOrElseGet should return other" ).isEqualTo( Collections.singletonList( 3 ) ); + } + } +}