-4

I have an annotated class that implements an interface with a read-only property named .id() that is generic so I can pull different types of ids in other parts of the program.

This entire interface should be ignored by Jackson. But instead I get the following error message:

java.util.concurrent.ExecutionException: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of my.company.Identifiable (no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: java.util.HashSet[0])

I have tried all the solutions found here when searching for that exception as well as the entire first two pages from Google. None of them address the exact problem I am having and I have been unable to interpalate a solution for my specific problem from any of them, short of a CustomDeserializer which I would rather not have to write.

I tried using JsonTypeInfo but I have never had to use that annotation before and can not figure out what I am supposed to do with it. The solutions that uses are slightly different from mine, where they actually want the interface property instead of ignoring it.

In some classes there is no actual id member variable, it is just a method to return something that is considered the id for another part of the program. ID<String> in some cases and ID<Integer> in others.

I have tried annotating with @JsonProperty(access = Access.READ_ONLY) as well as the @JsonIgnore and the @JsonIgnoreProperties({"id"}) none of them change the exception. I also tried all the mode settings in @JsonCreator, none worked.

The interface is defined as:

@JsonIgnoreProperties({"id"})
public interface Identifiable<T>
{
    @JsonIgnore
    public T id();
}

An example class is defined as:

@JsonIgnoreProperties(ignoreUnknown = true)
public class User implements Identifiable<ID<String>>
{
    @JsonCreator
    public User(@JsonProperty("LoginName") final String loginName,
                @JsonProperty("Title") final String name,
                @JsonProperty("Email") final String email)
/* lots of irrelevant code redacted */

    @JsonIgnore
    @Override
    public ID<String> id()
    {
        return new ID.from(this.name);
    }
}

This what the binding code looks like:

final HttpResponse response = req.execute();
final JsonNode root = this.om.readTree(response.getContent());
final JsonNode results = root.get("d").get("results");
final Set<V> values = this.om.readValue(this.om.treeAsTokens(results), 
                                        new TypeReference<Set<V>>() {});

Where V is User in this case and results is an Array.

Deserialization of this and a couple other classes worked fine before I added the Identifiable<T> interface, they they all broke with this same exception.

This is not an abstract class, every method is implemented. I think I have put the @JsonIgnore everywhere I can that is applicable.

I still get that exception and do not know how to solve it.

I have a feeling that there is something in the @JsonTypeInfo annotation that might fix this but the examples and javadoc are not written for someone that does not already know when or how to use the annotation.

What am I missing?

  • Make `id` [`transient`](https://stackoverflow.com/q/910374/2970947)? – Elliott Frisch Sep 21 '17 at 16:46
  • there is no actual `id` member variable, it is just a `method` to return something that is considered the `id` for another part of the program. `ID` in some cases and `ID` in others. I changed the example to show this case. –  Sep 21 '17 at 16:52
  • 2
    Is `V`, in reality, a type variable that `extends Identifiable`? And that is bound to `User` at some call site? The `TypeReference` can't actually capture `User` in that case. The type token hack captures the actual type in the source code, which in this case would be `V`, from which it would extract any generic bounds, and use that to the best of its abilities. See [this](https://stackoverflow.com/questions/19283606/does-jackson-typereference-work-when-extended) and similar for Gson [this](https://stackoverflow.com/questions/20773850/gson-typetoken-with-dynamic-arraylist-item-type) – Sotirios Delimanolis Sep 21 '17 at 18:13
  • in this case `V` is `User`, this is a working version that had `User` everywhere that `V`is now. I generified it to try and reused it because I need about a dozen classes that do the exact same thing except for the types. –  Sep 21 '17 at 18:44
  • 1
    If I use `new TypeReference>` (and some other basic assumptions), your sample parses the JSON fine. If `V` is a type variable (a method's generic type variable or a class'), it won't and I get the exception you described (for the reasons I described in my previous comments). As always, that [mcve] is critical :) – Sotirios Delimanolis Sep 21 '17 at 19:11
  • Thanks for all the pointers, I have solved it and will post the solution when I get a chance tomorrow. I got rid of the `Identifiable` interface completely and have what I think is a much better design. Avoiding inheritance is most always the better way to do things. –  Sep 21 '17 at 19:30

1 Answers1

2

You are trying to bind your JSON to an object of type Identifiable instead of an object of type User, it doesn't work because Identifiable is an interface. The problem isn't in the annotations it's where you are doing the binding.