Skip to content

Commit

Permalink
check for repeated logical subtype names FasterXML#3500
Browse files Browse the repository at this point in the history
  • Loading branch information
ancane committed May 29, 2022
1 parent da8bd5f commit 0303f98
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -621,14 +621,47 @@ public List<NamedType> findSubtypes(Annotated a)
JsonSubTypes t = _findAnnotation(a, JsonSubTypes.class);
if (t == null) return null;
JsonSubTypes.Type[] types = t.value();

if (t.allowRepeatedNames()) {
ArrayList<NamedType> result = new ArrayList<NamedType>(types.length);
for (JsonSubTypes.Type type : types) {
result.add(new NamedType(type.value(), type.name()));
// [databind#2761]: alternative set of names to use
for (String name : type.names()) {
result.add(new NamedType(type.value(), name));
}
}
return result;
} else {
return findSubtypesCheckRepeatedNames(a.getName(), types);
}
}

private List<NamedType> findSubtypesCheckRepeatedNames(String annotatedTypeName, JsonSubTypes.Type[] types)
{
ArrayList<NamedType> result = new ArrayList<NamedType>(types.length);
Set<String> seenNames = new HashSet<>();
for (JsonSubTypes.Type type : types) {
result.add(new NamedType(type.value(), type.name()));

if (!type.name().isEmpty() && seenNames.contains(type.name())) {
throw new IllegalArgumentException("Annotated type [" + annotatedTypeName + "] got repeated subtype name [" + type.name() + "]");
} else {
seenNames.add(type.name());
}

// [databind#2761]: alternative set of names to use
for (String name : type.names()) {
result.add(new NamedType(type.value(), name));

if (!name.isEmpty() && seenNames.contains(name)) {
throw new IllegalArgumentException("Annotated type [" + annotatedTypeName + "] got repeated subtype name [" + name + "]");
} else {
seenNames.add(name);
}
}
}

return result;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import com.fasterxml.jackson.databind.BaseMapTest;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;

import java.util.List;
Expand Down Expand Up @@ -72,6 +73,28 @@ static class BaseForNameAndNamesTest {
public MultiTypeName getData() { return data; }
}

static class WrapperForNotUniqueNamesTest {
List<BaseForNotUniqueNamesTest> base;
public List<BaseForNotUniqueNamesTest> getBase() { return base; }
}

static class BaseForNotUniqueNamesTest {
private String type;
public String getType() { return type; }

@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
property = "type"
)
@JsonSubTypes(value = {
@JsonSubTypes.Type(value = A.class, name = "a"),
@JsonSubTypes.Type(value = B.class, names = {"b","a"}),
}, allowRepeatedNames = false)
MultiTypeName data;
public MultiTypeName getData() { return data; }
}

/*
/**********************************************************
/* Test methods
Expand Down Expand Up @@ -133,4 +156,17 @@ public void testNameAndNames() throws Exception
verifyException(e, "Unrecognized field \"data\"");
}
}

public void testNotUniqueNameAndNames() throws Exception
{
String json = "{\"base\": [{\"type\":\"a\", \"data\": {\"x\": 5}}, {\"type\":\"b\", \"data\": {\"y\": 3.1}}, {\"type\":\"c\", \"data\": {\"y\": 33.8}}]}";

try {
MAPPER.readValue(json, WrapperForNotUniqueNamesTest.class);
fail("This serialisation should fail because of repeated subtype name");
} catch (InvalidDefinitionException e) {
verifyException(e, "Annotated type [data] got repeated subtype name [a]");
}
}

}

0 comments on commit 0303f98

Please sign in to comment.