From 13aa94742183fc5eedb3c991b55336d1b63a68dc Mon Sep 17 00:00:00 2001 From: Sjaak Derksen Date: Wed, 12 Sep 2018 16:26:09 +0200 Subject: [PATCH] #1569 Reproducer missing Immubable buildertype import (#1605) --- .../tests/FullFeatureCompilationTest.java | 3 + .../test/resources/fullFeatureTest/pom.xml | 2 + .../bugs/_1596/Issue1569BuilderProvider.java | 39 ++++ .../ap/test/bugs/_1596/Issue1596Test.java | 53 +++++ .../ap/test/bugs/_1596/ItemMapper.java | 20 ++ .../test/bugs/_1596/domain/ImmutableItem.java | 162 ++++++++++++++++ .../ap/test/bugs/_1596/domain/Item.java | 10 + .../test/bugs/_1596/dto/ImmutableItemDTO.java | 182 ++++++++++++++++++ .../ap/test/bugs/_1596/dto/ItemDTO.java | 10 + 9 files changed, 481 insertions(+) create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/Issue1569BuilderProvider.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/Issue1596Test.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/ItemMapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/domain/ImmutableItem.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/domain/Item.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/dto/ImmutableItemDTO.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/dto/ItemDTO.java diff --git a/integrationtest/src/test/java/org/mapstruct/itest/tests/FullFeatureCompilationTest.java b/integrationtest/src/test/java/org/mapstruct/itest/tests/FullFeatureCompilationTest.java index 76d5bd0a0..ba73357dc 100644 --- a/integrationtest/src/test/java/org/mapstruct/itest/tests/FullFeatureCompilationTest.java +++ b/integrationtest/src/test/java/org/mapstruct/itest/tests/FullFeatureCompilationTest.java @@ -53,6 +53,9 @@ public class FullFeatureCompilationTest { public Collection getAdditionalCommandLineArguments(ProcessorType processorType) { List additionalExcludes = new ArrayList<>(); + // SPI not working correctly here.. (not picked up) + additionalExcludes.add( "org/mapstruct/ap/test/bugs/_1596/*.java" ); + switch ( processorType ) { case ORACLE_JAVA_6: additionalExcludes.add( "org/mapstruct/ap/test/abstractclass/generics/*.java" ); diff --git a/integrationtest/src/test/resources/fullFeatureTest/pom.xml b/integrationtest/src/test/resources/fullFeatureTest/pom.xml index 7a1654c45..9a7b85426 100644 --- a/integrationtest/src/test/resources/fullFeatureTest/pom.xml +++ b/integrationtest/src/test/resources/fullFeatureTest/pom.xml @@ -24,6 +24,7 @@ x x x + x @@ -43,6 +44,7 @@ ${additionalExclude1} ${additionalExclude2} ${additionalExclude3} + ${additionalExclude4} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/Issue1569BuilderProvider.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/Issue1569BuilderProvider.java new file mode 100644 index 000000000..c3df53443 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/Issue1569BuilderProvider.java @@ -0,0 +1,39 @@ +/* + * Copyright MapStruct Authors. + * + * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0 + */ +package org.mapstruct.ap.test.bugs._1596; + +import javax.lang.model.element.Name; +import javax.lang.model.element.TypeElement; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; + +import org.mapstruct.ap.spi.BuilderInfo; +import org.mapstruct.ap.spi.BuilderProvider; +import org.mapstruct.ap.spi.ImmutablesBuilderProvider; + +public class Issue1569BuilderProvider extends ImmutablesBuilderProvider implements BuilderProvider { + + @Override + protected BuilderInfo findBuilderInfo(TypeElement typeElement, Elements elements, Types types) { + Name name = typeElement.getQualifiedName(); + if ( name.toString().endsWith( ".Item" ) ) { + BuilderInfo info = findBuilderInfoForImmutables( typeElement, elements, types ); + if ( info != null ) { + return info; + } + } + + return super.findBuilderInfo( typeElement, elements, types ); + } + + protected BuilderInfo findBuilderInfoForImmutables(TypeElement typeElement, Elements elements, Types types) { + TypeElement immutableElement = asImmutableElement( typeElement, elements ); + if ( immutableElement != null ) { + return super.findBuilderInfo( immutableElement, elements, types ); + } + return null; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/Issue1596Test.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/Issue1596Test.java new file mode 100644 index 000000000..f92648b21 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/Issue1596Test.java @@ -0,0 +1,53 @@ +/* + * Copyright MapStruct Authors. + * + * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0 + */ +package org.mapstruct.ap.test.bugs._1596; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mapstruct.ap.spi.AccessorNamingStrategy; +import org.mapstruct.ap.spi.BuilderProvider; +import org.mapstruct.ap.spi.ImmutablesAccessorNamingStrategy; +import org.mapstruct.ap.test.bugs._1596.domain.ImmutableItem; +import org.mapstruct.ap.test.bugs._1596.domain.Item; +import org.mapstruct.ap.test.bugs._1596.dto.ImmutableItemDTO; +import org.mapstruct.ap.test.bugs._1596.dto.ItemDTO; +import org.mapstruct.ap.testutil.IssueKey; +import org.mapstruct.ap.testutil.WithClasses; +import org.mapstruct.ap.testutil.WithServiceImplementation; +import org.mapstruct.ap.testutil.WithServiceImplementations; +import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Sjaak Derksen + */ +@WithClasses({ + ItemMapper.class, + Item.class, + ImmutableItem.class, + ItemDTO.class, + ImmutableItemDTO.class +}) +@RunWith(AnnotationProcessorTestRunner.class) +@IssueKey("1596") +@WithServiceImplementations( { + @WithServiceImplementation( provides = BuilderProvider.class, value = Issue1569BuilderProvider.class), + @WithServiceImplementation( provides = AccessorNamingStrategy.class, value = ImmutablesAccessorNamingStrategy.class) +}) +public class Issue1596Test { + + @Test + public void shouldIncludeBuildeType() { + + ItemDTO item = ImmutableItemDTO.builder().id( "test" ).build(); + + Item target = ItemMapper.INSTANCE.map( item ); + + assertThat( target ).isNotNull(); + assertThat( target.getId() ).isEqualTo( "test" ); + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/ItemMapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/ItemMapper.java new file mode 100644 index 000000000..00f647148 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/ItemMapper.java @@ -0,0 +1,20 @@ +/* + * Copyright MapStruct Authors. + * + * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0 + */ +package org.mapstruct.ap.test.bugs._1596; + +import org.mapstruct.Builder; +import org.mapstruct.Mapper; +import org.mapstruct.ap.test.bugs._1596.domain.Item; +import org.mapstruct.ap.test.bugs._1596.dto.ItemDTO; +import org.mapstruct.factory.Mappers; + +@Mapper( builder = @Builder) +public abstract class ItemMapper { + + public static final ItemMapper INSTANCE = Mappers.getMapper( ItemMapper.class ); + + public abstract Item map(ItemDTO itemDTO); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/domain/ImmutableItem.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/domain/ImmutableItem.java new file mode 100644 index 000000000..f0ea47428 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/domain/ImmutableItem.java @@ -0,0 +1,162 @@ +/* + * Copyright MapStruct Authors. + * + * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0 + */ +package org.mapstruct.ap.test.bugs._1596.domain; + +import java.util.ArrayList; +import java.util.List; + +/** + * Immutable implementation of {@link Item}. + *

+ * Use the builder to create immutable instances: + * {@code ImmutableItem.builder()}. + */ +@SuppressWarnings({"all"}) +public final class ImmutableItem extends Item { + private final String id; + + private ImmutableItem(String id) { + this.id = id; + } + + /** + * @return The value of the {@code id} attribute + */ + @Override + public String getId() { + return id; + } + + /** + * Copy the current immutable object by setting a value for the {@link Item#getId() id} attribute. + * A shallow reference equality check is used to prevent copying of the same value by returning {@code this}. + * @param value A new value for id + * @return A modified copy of the {@code this} object + */ + public final ImmutableItem withId(String value) { + if (this.id == value) return this; + return new ImmutableItem(value); + } + + /** + * This instance is equal to all instances of {@code ImmutableItem} that have equal attribute values. + * @return {@code true} if {@code this} is equal to {@code another} instance + */ + @Override + public boolean equals(Object another) { + if (this == another) return true; + return another instanceof ImmutableItem + && equalTo((ImmutableItem) another); + } + + private boolean equalTo(ImmutableItem another) { + return id.equals(another.id); + } + + /** + * Computes a hash code from attributes: {@code id}. + * @return hashCode value + */ + @Override + public int hashCode() { + int h = 5381; + h += (h << 5) + id.hashCode(); + return h; + } + + /** + * Prints the immutable value {@code Item} with attribute values. + * @return A string representation of the value + */ + @Override + public String toString() { + return "Item{" + + "id=" + id + + "}"; + } + + /** + * Creates an immutable copy of a {@link Item} value. + * Uses accessors to get values to initialize the new immutable instance. + * If an instance is already immutable, it is returned as is. + * @param instance The instance to copy + * @return A copied immutable Item instance + */ + public static ImmutableItem copyOf(Item instance) { + if (instance instanceof ImmutableItem) { + return (ImmutableItem) instance; + } + return ImmutableItem.builder() + .from(instance) + .build(); + } + + /** + * Creates a builder for {@link ImmutableItem ImmutableItem}. + * @return A new ImmutableItem builder + */ + public static ImmutableItem.Builder builder() { + return new ImmutableItem.Builder(); + } + + /** + * Builds instances of type {@link ImmutableItem ImmutableItem}. + * Initialize attributes and then invoke the {@link #build()} method to create an + * immutable instance. + *

{@code Builder} is not thread-safe and generally should not be stored in a field or collection, + * but instead used immediately to create instances. + */ + public static final class Builder { + private static final long INIT_BIT_ID = 0x1L; + private long initBits = 0x1L; + + private String id; + + private Builder() { + } + + /** + * Fill a builder with attribute values from the provided {@code Item} instance. + * Regular attribute values will be replaced with those from the given instance. + * Absent optional values will not replace present values. + * @param instance The instance from which to copy values + * @return {@code this} builder for use in a chained invocation + */ + public final Builder from(Item instance) { + id(instance.getId()); + return this; + } + + /** + * Initializes the value for the {@link Item#getId() id} attribute. + * @param id The value for id + * @return {@code this} builder for use in a chained invocation + */ + public final Builder id(String id) { + this.id = id; + initBits &= ~INIT_BIT_ID; + return this; + } + + /** + * Builds a new {@link ImmutableItem ImmutableItem}. + * @return An immutable instance of Item + * @throws java.lang.IllegalStateException if any required attributes are missing + */ + public ImmutableItem build() { + if (initBits != 0) { + throw new IllegalStateException(formatRequiredAttributesMessage()); + } + return new ImmutableItem(id); + } + + private String formatRequiredAttributesMessage() { + List attributes = new ArrayList(); + if ((initBits & INIT_BIT_ID) != 0) attributes.add("id"); + return "Cannot build Item, some of required attributes are not set " + attributes; + } + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/domain/Item.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/domain/Item.java new file mode 100644 index 000000000..6c5be0381 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/domain/Item.java @@ -0,0 +1,10 @@ +/* + * Copyright MapStruct Authors. + * + * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0 + */ +package org.mapstruct.ap.test.bugs._1596.domain; + +public abstract class Item { + public abstract String getId(); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/dto/ImmutableItemDTO.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/dto/ImmutableItemDTO.java new file mode 100644 index 000000000..4d84af347 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/dto/ImmutableItemDTO.java @@ -0,0 +1,182 @@ +/* + * Copyright MapStruct Authors. + * + * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0 + */ +package org.mapstruct.ap.test.bugs._1596.dto; + +import java.util.ArrayList; +import java.util.List; + +/** + * Immutable implementation of {@link ItemDTO}. + *

+ * Use the builder to create immutable instances: + * {@code ImmutableItemDTO.builder()}. + */ +@SuppressWarnings({ "all" }) +public final class ImmutableItemDTO extends ItemDTO { + private final String id; + + private ImmutableItemDTO(String id) { + this.id = id; + } + + /** + * @return The value of the {@code id} attribute + */ + @Override + public String getId() { + return id; + } + + /** + * Copy the current immutable object by setting a value for the {@link ItemDTO#getId() id} attribute. + * A shallow reference equality check is used to prevent copying of the same value by returning {@code this}. + * + * @param value A new value for id + * + * @return A modified copy of the {@code this} object + */ + public final ImmutableItemDTO withId(String value) { + if ( this.id == value ) { + return this; + } + return new ImmutableItemDTO( value ); + } + + /** + * This instance is equal to all instances of {@code ImmutableItemDTO} that have equal attribute values. + * + * @return {@code true} if {@code this} is equal to {@code another} instance + */ + @Override + public boolean equals(Object another) { + if ( this == another ) { + return true; + } + return another instanceof ImmutableItemDTO + && equalTo( (ImmutableItemDTO) another ); + } + + private boolean equalTo(ImmutableItemDTO another) { + return id.equals( another.id ); + } + + /** + * Computes a hash code from attributes: {@code id}. + * + * @return hashCode value + */ + @Override + public int hashCode() { + int h = 5381; + h += ( h << 5 ) + id.hashCode(); + return h; + } + + /** + * Prints the immutable value {@code ItemDTO} with attribute values. + * + * @return A string representation of the value + */ + @Override + public String toString() { + return "ItemDTO{" + + "id=" + id + + "}"; + } + + /** + * Creates an immutable copy of a {@link ItemDTO} value. + * Uses accessors to get values to initialize the new immutable instance. + * If an instance is already immutable, it is returned as is. + * + * @param instance The instance to copy + * + * @return A copied immutable ItemDTO instance + */ + public static ImmutableItemDTO copyOf(ItemDTO instance) { + if ( instance instanceof ImmutableItemDTO ) { + return (ImmutableItemDTO) instance; + } + return ImmutableItemDTO.builder() + .from( instance ) + .build(); + } + + /** + * Creates a builder for {@link ImmutableItemDTO ImmutableItemDTO}. + * + * @return A new ImmutableItemDTO builder + */ + public static ImmutableItemDTO.Builder builder() { + return new ImmutableItemDTO.Builder(); + } + + /** + * Builds instances of type {@link ImmutableItemDTO ImmutableItemDTO}. + * Initialize attributes and then invoke the {@link #build()} method to create an + * immutable instance. + *

{@code Builder} is not thread-safe and generally should not be stored in a field or collection, + * but instead used immediately to create instances. + */ + public static final class Builder { + private static final long INIT_BIT_ID = 0x1L; + private long initBits = 0x1L; + + private String id; + + private Builder() { + } + + /** + * Fill a builder with attribute values from the provided {@code ItemDTO} instance. + * Regular attribute values will be replaced with those from the given instance. + * Absent optional values will not replace present values. + * + * @param instance The instance from which to copy values + * + * @return {@code this} builder for use in a chained invocation + */ + public final Builder from(ItemDTO instance) { + id( instance.getId() ); + return this; + } + + /** + * Initializes the value for the {@link ItemDTO#getId() id} attribute. + * + * @param id The value for id + * + * @return {@code this} builder for use in a chained invocation + */ + public final Builder id(String id) { + this.id = id; + initBits &= ~INIT_BIT_ID; + return this; + } + + /** + * Builds a new {@link ImmutableItemDTO ImmutableItemDTO}. + * + * @return An immutable instance of ItemDTO + * + * @throws java.lang.IllegalStateException if any required attributes are missing + */ + public ImmutableItemDTO build() { + if ( initBits != 0 ) { + throw new IllegalStateException( formatRequiredAttributesMessage() ); + } + return new ImmutableItemDTO( id ); + } + + private String formatRequiredAttributesMessage() { + List attributes = new ArrayList(); + if ( ( initBits & INIT_BIT_ID ) != 0 ) { + attributes.add( "id" ); + } + return "Cannot build ItemDTO, some of required attributes are not set " + attributes; + } + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/dto/ItemDTO.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/dto/ItemDTO.java new file mode 100644 index 000000000..9cbed4ae5 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_1596/dto/ItemDTO.java @@ -0,0 +1,10 @@ +/* + * Copyright MapStruct Authors. + * + * Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0 + */ +package org.mapstruct.ap.test.bugs._1596.dto; + +public abstract class ItemDTO { + public abstract String getId(); +}