From 5c82b2870e2d34b7713e7777673dd7e4af9d5d09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vojt=C4=9Bch=20Habarta?= Date: Tue, 6 Aug 2019 21:50:13 +0200 Subject: [PATCH] Allow regular TS types as type arguments in `customTypeMappings` (#384) example: `Map` --- .../generator/CustomMappingTypeProcessor.java | 76 +++++++++---------- .../typescript/generator/Settings.java | 14 +--- .../typescript/generator/util/Utils.java | 19 +++-- .../GenericCustomTypeMappingsTest.java | 13 +++- 4 files changed, 66 insertions(+), 56 deletions(-) diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/CustomMappingTypeProcessor.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/CustomMappingTypeProcessor.java index 0e211fe6f..4fdcfaba6 100644 --- a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/CustomMappingTypeProcessor.java +++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/CustomMappingTypeProcessor.java @@ -1,7 +1,8 @@ package cz.habarta.typescript.generator; -import java.lang.reflect.ParameterizedType; +import cz.habarta.typescript.generator.util.Pair; +import cz.habarta.typescript.generator.util.Utils; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; @@ -22,47 +23,46 @@ public CustomMappingTypeProcessor(List customMapping @Override public Result processType(Type javaType, Context context) { - if (javaType instanceof Class) { - final Class javaClass = (Class) javaType; - final Settings.CustomTypeMapping mapping = customMappings.get(javaClass.getName()); - if (mapping != null) { - return new Result(new TsType.BasicType(mapping.tsType.rawName)); - } + final Pair, List> rawClassAndTypeArguments = Utils.getRawClassAndTypeArguments(javaType); + if (rawClassAndTypeArguments == null) { + return null; + } + final Class rawClass = rawClassAndTypeArguments.getValue1(); + final List typeArguments = rawClassAndTypeArguments.getValue2(); + final Settings.CustomTypeMapping mapping = customMappings.get(rawClass.getName()); + if (mapping == null) { + return null; } - if (javaType instanceof ParameterizedType) { - final ParameterizedType parameterizedType = (ParameterizedType) javaType; - if (parameterizedType.getRawType() instanceof Class) { - final Class javaClass = (Class) parameterizedType.getRawType(); - final Settings.CustomTypeMapping mapping = customMappings.get(javaClass.getName()); - if (mapping != null) { - final List> discoveredClasses = new ArrayList<>(); - final Function processGenericParameter = index -> { - final Type typeArgument = parameterizedType.getActualTypeArguments()[index]; - final TypeProcessor.Result typeArgumentResult = context.processType(typeArgument); - discoveredClasses.addAll(typeArgumentResult.getDiscoveredClasses()); - return typeArgumentResult.getTsType(); - }; - if (mapping.tsType.typeParameters != null) { - final List tsTypeArguments = new ArrayList<>(); - for (String typeParameter : mapping.tsType.typeParameters) { - final int index = mapping.javaType.typeParameters.indexOf(typeParameter); - final TsType tsType = processGenericParameter.apply(index); - tsTypeArguments.add(tsType); - } - return new Result(new TsType.GenericBasicType(mapping.tsType.rawName, tsTypeArguments), discoveredClasses); - } else { - final int index = mapping.javaType.typeParameters.indexOf(mapping.tsType.rawName); - if (index != -1) { - final TsType tsType = processGenericParameter.apply(index); - return new Result(tsType, discoveredClasses); - } else { - return new Result(new TsType.BasicType(mapping.tsType.rawName), discoveredClasses); - } - } + + final List> discoveredClasses = new ArrayList<>(); + final Function processGenericParameter = index -> { + final Type typeArgument = typeArguments.get(index); + final TypeProcessor.Result typeArgumentResult = context.processType(typeArgument); + discoveredClasses.addAll(typeArgumentResult.getDiscoveredClasses()); + return typeArgumentResult.getTsType(); + }; + if (mapping.tsType.typeParameters != null) { + final List tsTypeArguments = new ArrayList<>(); + for (String typeParameter : mapping.tsType.typeParameters) { + final TsType tsType; + final int index = mapping.javaType.indexOfTypeParameter(typeParameter); + if (index != -1) { + tsType = processGenericParameter.apply(index); + } else { + tsType = new TsType.VerbatimType(typeParameter); } + tsTypeArguments.add(tsType); + } + return new Result(new TsType.GenericBasicType(mapping.tsType.rawName, tsTypeArguments), discoveredClasses); + } else { + final int index = mapping.javaType.indexOfTypeParameter(mapping.tsType.rawName); + if (index != -1) { + final TsType tsType = processGenericParameter.apply(index); + return new Result(tsType, discoveredClasses); + } else { + return new Result(new TsType.BasicType(mapping.tsType.rawName), discoveredClasses); } } - return null; } } diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/Settings.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/Settings.java index 2e4062e90..025789e7d 100644 --- a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/Settings.java +++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/Settings.java @@ -151,6 +151,10 @@ public GenericName(String rawName, List typeParameters) { this.rawName = Objects.requireNonNull(rawName); this.typeParameters = typeParameters; } + + public int indexOfTypeParameter(String typeParameter) { + return typeParameters != null ? typeParameters.indexOf(typeParameter) : -1; + } } private static class TypeScriptGeneratorURLClassLoader extends URLClassLoader { @@ -413,16 +417,6 @@ public List getValidatedCustomTypeMappings() { "Wrong number of specified generic parameters, required: %s, found: %s. Correct format is: '%s'", required, specified, signature)); } - if (genericTsName.typeParameters != null) { - final Set parameters = Stream.of(cls.getTypeParameters()) - .map(TypeVariable::getName) - .collect(Collectors.toSet()); - for (String parameter : genericTsName.typeParameters) { - if (!parameters.contains(parameter)) { - throw new RuntimeException(String.format("Unknown generic type parameter '%s'", parameter)); - } - } - } validatedCustomTypeMappings.add(new CustomTypeMapping(genericJavaName, genericTsName)); } catch (Exception e) { throw new RuntimeException(String.format("Failed to parse configured custom type mapping '%s:%s': %s", javaName, tsName, e.getMessage()), e); diff --git a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/util/Utils.java b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/util/Utils.java index 67f96b1ff..fcfb09b1c 100644 --- a/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/util/Utils.java +++ b/typescript-generator-core/src/main/java/cz/habarta/typescript/generator/util/Utils.java @@ -81,13 +81,20 @@ private static String trimSlash(String path) { } public static Class getRawClassOrNull(Type type) { - if (type instanceof Class) { - return (Class) type; - } else if (type instanceof ParameterizedType) { + final Pair, List> rawClassAndTypeArguments = getRawClassAndTypeArguments(type); + return rawClassAndTypeArguments != null ? rawClassAndTypeArguments.getValue1() : null; + } + + public static Pair, List> getRawClassAndTypeArguments(Type type) { + if (type instanceof Class) { + final Class javaClass = (Class) type; + return Pair.of(javaClass, Collections.emptyList()); + } + if (type instanceof ParameterizedType) { final ParameterizedType parameterizedType = (ParameterizedType) type; - final Type rawType = parameterizedType.getRawType(); - if (rawType instanceof Class) { - return (Class) rawType; + if (parameterizedType.getRawType() instanceof Class) { + final Class javaClass = (Class) parameterizedType.getRawType(); + return Pair.of(javaClass, Arrays.asList(parameterizedType.getActualTypeArguments())); } } return null; diff --git a/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/GenericCustomTypeMappingsTest.java b/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/GenericCustomTypeMappingsTest.java index 4f0685c3c..e6fe74c62 100644 --- a/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/GenericCustomTypeMappingsTest.java +++ b/typescript-generator-core/src/test/java/cz/habarta/typescript/generator/GenericCustomTypeMappingsTest.java @@ -70,10 +70,8 @@ private static class IdRepresentation { public void testInvalidGenerics() { testInvalid("NonExisting", "string"); testInvalid(NonGeneric.class.getName() + "", "string"); - testInvalid(NonGeneric.class.getName(), "string"); testInvalid(Generic2.class.getName(), "string"); testInvalid(Generic2.class.getName() + "", "string"); - testInvalid(Generic2.class.getName() + "", "string"); } private static void testInvalid(String javaName, String tsName) { @@ -103,7 +101,18 @@ public void testUnwrap() { Assert.assertTrue(output.contains("generic: number")); } + @Test + public void testMapStringString() { + final Settings settings = TestUtils.settings(); + settings.customTypeMappings = Collections.singletonMap("cz.habarta.typescript.generator.GenericCustomTypeMappingsTest$NonGeneric", "Map"); + final String output = new TypeScriptGenerator(settings).generateTypeScript(Input.from(NonGenericUsage.class)); + Assert.assertTrue(output.contains("nonGeneric: Map")); + } + private static class NonGeneric {} + private static class NonGenericUsage { + public NonGeneric nonGeneric; + } private static class Generic2 {} private static class Usage { public Generic2 generic;