From ab528678318cb0983f50767b8170ab4697ba4e75 Mon Sep 17 00:00:00 2001 From: Chris DeLashmutt Date: Sat, 19 Mar 2022 06:51:19 -0400 Subject: [PATCH] #2748 Support mapping map keys with invalid chars for methods --- .../mapstruct/ap/internal/util/Strings.java | 14 +++++- .../ap/internal/util/StringsTest.java | 3 ++ .../ap/test/bugs/_2748/Issue2748Mapper.java | 48 +++++++++++++++++++ .../ap/test/bugs/_2748/Issue2748Test.java | 36 ++++++++++++++ 4 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2748/Issue2748Mapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/bugs/_2748/Issue2748Test.java diff --git a/processor/src/main/java/org/mapstruct/ap/internal/util/Strings.java b/processor/src/main/java/org/mapstruct/ap/internal/util/Strings.java index 42727ed81..88e0bdf6f 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/util/Strings.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/util/Strings.java @@ -183,7 +183,19 @@ public class Strings { if ( firstAlphabeticIndex < identifier.length()) { // If it is not consisted of only underscores - return identifier.substring( firstAlphabeticIndex ).replace( "[]", "Array" ); + String firstAlphaString = identifier.substring( firstAlphabeticIndex ).replace( "[]", "Array" ); + + StringBuilder sb = new StringBuilder( firstAlphaString.length() ); + for ( int i = 0; i < firstAlphaString.length(); i++ ) { + int codePoint = firstAlphaString.codePointAt( i ); + if ( Character.isJavaIdentifierPart( codePoint ) || codePoint == '.') { + sb.appendCodePoint( codePoint ); + } + else { + sb.append( '_' ); + } + } + return sb.toString(); } return identifier.replace( "[]", "Array" ); diff --git a/processor/src/test/java/org/mapstruct/ap/internal/util/StringsTest.java b/processor/src/test/java/org/mapstruct/ap/internal/util/StringsTest.java index 687b63f79..524fd193a 100644 --- a/processor/src/test/java/org/mapstruct/ap/internal/util/StringsTest.java +++ b/processor/src/test/java/org/mapstruct/ap/internal/util/StringsTest.java @@ -72,6 +72,7 @@ public class StringsTest { assertThat( Strings.getSafeVariableName( "__Test" ) ).isEqualTo( "test" ); assertThat( Strings.getSafeVariableName( "_0Test" ) ).isEqualTo( "test" ); assertThat( Strings.getSafeVariableName( "_0123Test" ) ).isEqualTo( "test" ); + assertThat( Strings.getSafeVariableName( "bad/test" ) ).isEqualTo( "bad_test" ); } @Test @@ -94,6 +95,7 @@ public class StringsTest { assertThat( Strings.getSafeVariableName( "__0Test", Arrays.asList( "test" ) ) ).isEqualTo( "test1" ); assertThat( Strings.getSafeVariableName( "___0", new ArrayList<>() ) ).isEqualTo( "___0" ); assertThat( Strings.getSafeVariableName( "__0123456789Test", Arrays.asList( "test" ) ) ).isEqualTo( "test1" ); + assertThat( Strings.getSafeVariableName( "bad/test", Arrays.asList( "bad_test" ) ) ).isEqualTo( "bad_test1" ); } @Test @@ -110,6 +112,7 @@ public class StringsTest { assertThat( Strings.sanitizeIdentifierName( "_0int[]" ) ).isEqualTo( "intArray" ); assertThat( Strings.sanitizeIdentifierName( "__0int[]" ) ).isEqualTo( "intArray" ); assertThat( Strings.sanitizeIdentifierName( "___0" ) ).isEqualTo( "___0" ); + assertThat( Strings.sanitizeIdentifierName( "bad/test" ) ).isEqualTo( "bad_test" ); } @Test diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2748/Issue2748Mapper.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2748/Issue2748Mapper.java new file mode 100644 index 000000000..0062667df --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2748/Issue2748Mapper.java @@ -0,0 +1,48 @@ +/* + * 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._2748; + +import java.util.Map; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +/** + * @author Filip Hrisafov + */ +@Mapper +public interface Issue2748Mapper { + + Issue2748Mapper INSTANCE = Mappers.getMapper( Issue2748Mapper.class ); + + @Mapping(target = "specificValue", source = "annotations.specific/value") + Target map(Source source); + + class Target { + private final String specificValue; + + public Target(String specificValue) { + this.specificValue = specificValue; + } + + public String getSpecificValue() { + return specificValue; + } + } + + class Source { + private final Map annotations; + + public Source(Map annotations) { + this.annotations = annotations; + } + + public Map getAnnotations() { + return annotations; + } + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/bugs/_2748/Issue2748Test.java b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2748/Issue2748Test.java new file mode 100644 index 000000000..4bda2cd43 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/bugs/_2748/Issue2748Test.java @@ -0,0 +1,36 @@ +/* + * 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._2748; + +import java.util.Collections; +import java.util.Map; + +import org.mapstruct.ap.testutil.IssueKey; +import org.mapstruct.ap.testutil.ProcessorTest; +import org.mapstruct.ap.testutil.WithClasses; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Filip Hrisafov + */ +@IssueKey("2748") +@WithClasses( { + Issue2748Mapper.class +} ) +class Issue2748Test { + + @ProcessorTest + void shouldMapNonJavaIdentifier() { + Map annotations = Collections.singletonMap( "specific/value", "value" ); + Issue2748Mapper.Source source = new Issue2748Mapper.Source( annotations ); + + Issue2748Mapper.Target target = Issue2748Mapper.INSTANCE.map( source ); + + assertThat( target ).isNotNull(); + assertThat( target.getSpecificValue() ).isEqualTo( "value" ); + } +}