From 6b4fc1189ae9073a3b5b2527d1754da3a4b9358a Mon Sep 17 00:00:00 2001 From: Eugene Lukash Date: Mon, 22 May 2023 19:07:51 -0400 Subject: [PATCH] #1454 fixing ad-hoc parsing --- .../org/immutables/generator/SourceTypes.java | 62 ++++++++++++++++++- .../HasTypeAnnotationWithAttributes.java | 10 +++ .../HasTypeAnnotationWithAttributes.java | 10 +++ .../value/processor/encode/TypeTest.java | 27 ++++++++ 4 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 value-fixture/src-java-17/org/immutables/fixture/HasTypeAnnotationWithAttributes.java create mode 100644 value-fixture/src/org/immutables/fixture/generics/HasTypeAnnotationWithAttributes.java diff --git a/generator/src/org/immutables/generator/SourceTypes.java b/generator/src/org/immutables/generator/SourceTypes.java index 100a911c5..405bb44dc 100644 --- a/generator/src/org/immutables/generator/SourceTypes.java +++ b/generator/src/org/immutables/generator/SourceTypes.java @@ -29,9 +29,30 @@ public static Entry> extract(CharSequence typeString) { StringBuilder typeArgument = new StringBuilder(); List typeArguments = Lists.newArrayList(); int anglesOpened = 0; + int parensOpened = 0; chars: for (int i = 0; i < typeString.length(); i++) { char c = typeString.charAt(i); switch (c) { + case '"': + case '\'': + i = transferStringLiteral(anglesOpened == 0 ? typeName : typeArgument, typeString, c, i + 1) - 1; + break; + case '(': + parensOpened++; + if (anglesOpened == 0) { + typeName.append(c); + } else { + typeArgument.append(c); + } + break; + case ')': + parensOpened--; + if (anglesOpened == 0) { + typeName.append(c); + } else { + typeArgument.append(c); + } + break; case '<': if (++anglesOpened > 1) { typeArgument.append(c); @@ -45,15 +66,31 @@ public static Entry> extract(CharSequence typeString) { } break; case ',': - if (anglesOpened == 1) { + if (parensOpened > 0) { + if (anglesOpened == 0) { + typeName.append(c); + } else { + typeArgument.append(c); + } + } else if (anglesOpened == 1) { typeArguments.add(typeArgument.toString()); typeArgument = new StringBuilder(); } else { typeArgument.append(c); } break; - case ' ':// not sure about this one - if (anglesOpened > 1) { + case ' ': + if (anglesOpened == 0) { + typeName.append(c); + } else if (anglesOpened == 1) { + if (parensOpened > 0) { + typeArgument.append(c); + } else { + if (typeArgument.length() > 0 && typeArgument.charAt(typeArgument.length() - 1) == ')') { + typeArgument.append(c); + } + } + } else { typeArgument.append(c); } break; @@ -72,6 +109,25 @@ public static Entry> extract(CharSequence typeString) { return Maps.immutableEntry(typeName.toString(), typeArguments); } + private static int transferStringLiteral(StringBuilder target, CharSequence typeString, char end, int i) { + target.append(end); + for (; i < typeString.length(); i++) { + char c = typeString.charAt(i); + if (c == '\\') { // for each escape, we expected that next symbol will always exist and + target.append(c); + c = typeString.charAt(++i); + target.append(c); + } else if (c == end) { + target.append(c); + i++; + break; + } else { + target.append(c); + } + } + return i; + } + public static String stringify(Entry> types) { if (types.getValue().isEmpty()) { return types.getKey(); diff --git a/value-fixture/src-java-17/org/immutables/fixture/HasTypeAnnotationWithAttributes.java b/value-fixture/src-java-17/org/immutables/fixture/HasTypeAnnotationWithAttributes.java new file mode 100644 index 000000000..35f4cc850 --- /dev/null +++ b/value-fixture/src-java-17/org/immutables/fixture/HasTypeAnnotationWithAttributes.java @@ -0,0 +1,10 @@ +package org.immutables.fixture; + +import java.util.Map; +import javax.validation.constraints.Size; +import org.immutables.value.Value; + +@Value.Immutable +public interface HasTypeAnnotationWithAttributes { + Map<@Size(min = 1, max = 99) String, Integer> map(); +} diff --git a/value-fixture/src/org/immutables/fixture/generics/HasTypeAnnotationWithAttributes.java b/value-fixture/src/org/immutables/fixture/generics/HasTypeAnnotationWithAttributes.java new file mode 100644 index 000000000..ca18a743d --- /dev/null +++ b/value-fixture/src/org/immutables/fixture/generics/HasTypeAnnotationWithAttributes.java @@ -0,0 +1,10 @@ +package org.immutables.fixture.generics; + +import java.util.Map; +import javax.validation.constraints.Size; +import org.immutables.value.Value; + +@Value.Immutable +public interface HasTypeAnnotationWithAttributes { + Map<@Size(min = 1, max = 99) String, Integer> map(); +} diff --git a/value-processor/test/org/immutables/value/processor/encode/TypeTest.java b/value-processor/test/org/immutables/value/processor/encode/TypeTest.java index 1ba767b63..6fafb37a8 100644 --- a/value-processor/test/org/immutables/value/processor/encode/TypeTest.java +++ b/value-processor/test/org/immutables/value/processor/encode/TypeTest.java @@ -15,8 +15,11 @@ */ package org.immutables.value.processor.encode; +import java.util.List; +import java.util.Map; import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; +import org.immutables.generator.SourceTypes; import org.immutables.value.processor.encode.Type.Defined; import org.immutables.value.processor.encode.Type.Primitive; import org.immutables.value.processor.encode.Type.Reference; @@ -36,6 +39,30 @@ public class TypeTest { Type.Parser parser = new Type.Parser(factory, parameters); + @Test + public void sourceTypeAdHocParsing() { + Map.Entry> extract = + SourceTypes.extract("Map"); + check(extract.getKey()).is("Map"); + check(extract.getValue()).isOf("java.lang.@org.it.Size(a=1, b=2) String", "Integer"); + + Map.Entry> extract2 = + SourceTypes.extract("List<@org.it.Size(a=1, b=2) java.lang.String>"); + + check(extract2.getKey()).is("List"); + check(extract2.getValue()).isOf("@org.it.Size(a=1, b=2) java.lang.String"); + + Map.Entry> extract3 = + SourceTypes.extract("Map, String>"); + + check(extract3.getValue()).isOf("List", "String"); + + Map.Entry> extract4 = + SourceTypes.extract("List<@Size(a='\\'', c=\"abc, z='\") String>"); + check(extract4.getKey()).is("List"); + check(extract4.getValue()).isOf("@Size(a='\\'', c=\"abc, z='\") String"); + } + @Test public void templateMatch() { Type template = parser.parse("java.lang.Iterable");