Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for #181 - Correctly handling parameterized interfaces #182

Merged
merged 1 commit into from
Oct 1, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,12 @@ private Map<Type, List<BeanModel>> createChildrenMap(Model model) {
final Map<Type, List<BeanModel>> children = new LinkedHashMap<>();
for (BeanModel bean : model.getBeans()) {
for (Type ancestor : bean.getParentAndInterfaces()) {
if (!children.containsKey(ancestor)) {
children.put(ancestor, new ArrayList<BeanModel>());
Type processedAncestor = processTypeForDescendantLookup(ancestor);

if (!children.containsKey(processedAncestor)) {
children.put(processedAncestor, new ArrayList<BeanModel>());
}
children.get(ancestor).add(bean);
children.get(processedAncestor).add(bean);
}
}
return children;
Expand Down Expand Up @@ -186,10 +188,21 @@ private List<TsPropertyModel> processProperties(SymbolTable symbolTable, Model m
return properties;
}

/**
* Given a type, returns the type that should be used for the purpose of looking up implementations of that type.
*/
private static Type processTypeForDescendantLookup(Type type) {
if (type instanceof ParameterizedType) {
return ((ParameterizedType) type).getRawType();
} else {
return type;
}
}

private static List<BeanModel> getSelfAndDescendants(BeanModel bean, Map<Type, List<BeanModel>> children) {
final List<BeanModel> descendants = new ArrayList<>();
descendants.add(bean);
final List<BeanModel> directDescendants = children.get(bean.getOrigin());
final List<BeanModel> directDescendants = children.get(processTypeForDescendantLookup(bean.getOrigin()));
if (directDescendants != null) {
for (BeanModel descendant : directDescendants) {
descendants.addAll(getSelfAndDescendants(descendant, children));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@

package cz.habarta.typescript.generator;

import java.lang.reflect.*;
import java.util.*;
import org.junit.*;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import cz.habarta.typescript.generator.compiler.ModelCompiler;
import cz.habarta.typescript.generator.emitter.TsModel;
import cz.habarta.typescript.generator.parser.Jackson2Parser;
import cz.habarta.typescript.generator.parser.Model;
import org.hamcrest.CoreMatchers;
import org.junit.Assert;
import org.junit.Test;

import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

public class ModelCompilerTest {

Expand Down Expand Up @@ -37,6 +47,46 @@ public void testExclusionPattern() throws Exception {
Assert.assertEquals("{ [index: string]: any }[]", TestUtils.compileType(settings, javaType).toString());
}

@Test
public void testIntermediateInterfacesWithoutTypeParams() throws Exception {
final Settings settings = TestUtils.settings();

final Jackson2Parser jacksonParser = new Jackson2Parser(settings, new DefaultTypeProcessor());
final Model model = jacksonParser.parseModel(Implementation.class);
final ModelCompiler modelCompiler = new TypeScriptGenerator(settings).getModelCompiler();

final TsModel result = modelCompiler.javaToTypeScript(model);

Assert.assertThat(
result.getBean(WithoutTypeParam.class).getProperties().get(0).tsType,
CoreMatchers.instanceOf(TsType.UnionType.class)
);
}

@Test
public void testIntermediateInterfacesWithTypeParams() throws Exception {
final Settings settings = TestUtils.settings();

final Jackson2Parser jacksonParser = new Jackson2Parser(settings, new DefaultTypeProcessor());
final Model model = jacksonParser.parseModel(Implementation.class);
final ModelCompiler modelCompiler = new TypeScriptGenerator(settings).getModelCompiler();

final TsModel result = modelCompiler.javaToTypeScript(model);

Assert.assertThat(
result.getBean(WithTypeParam.class).getProperties().get(0).tsType,
CoreMatchers.instanceOf(TsType.UnionType.class)
);
}

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY)
private static interface WithoutTypeParam {}

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY)
private static interface WithTypeParam<T> {}

private static class Implementation implements WithTypeParam<Integer>, WithoutTypeParam {}

private static Settings getTestSettings(String... excludedClassNames) {
final Settings settings = TestUtils.settings();
settings.mapDate = DateMapping.asString;
Expand Down