Question

This is Jackson 2.3.3. I have recently learned about mixin annotations in Jackson am I'm trying to apply it to a class. Without success so far however. The class in question is a static class into another class:

public static class Report
{
    // Some non relevant public static final fields, then:

    public final int totalRuns;
    public final int totalInvocations;
    public final int totalMatches;
    public final int totalMismatches;
    public final double matchShare;
    public final int reinvocations;
    public final int rematches;
    public final int remismatches;
    public final double reinvocationShare;
    public final long totalNanoTime;
    public final List<RuleReport> ruleReports;

    public Report(final int totalRuns, final int totalMatches,
        final int totalMismatches, final int rematches,
        final int remismatches, final long totalNanoTime,
        final List<RuleReport> ruleReports)
    {
        this.totalRuns = totalRuns;
        this.totalInvocations = totalMatches + totalMismatches;
        this.totalMatches = totalMatches;
        this.totalMismatches = totalMismatches;
        this.matchShare = (double) totalMatches / (double) totalInvocations;
        this.reinvocations = rematches + remismatches;
        this.rematches = rematches;
        this.remismatches = remismatches;
        this.reinvocationShare = (double) reinvocations
            / (double) totalInvocations;
        this.totalNanoTime = totalNanoTime;
        this.ruleReports = ruleReports;
    }
    // Other, non relevant methods
}

And there are no other constructors. Therefore I wrote my mixin class as such:

public abstract class ProfilingReportMixin
{
    @JsonProperty("runs")
    private int totalRuns;
    @JsonIgnore
    private int totalInvocations;
    @JsonProperty("matches")
    private int totalMatches;
    @JsonProperty("mismatches")
    private int totalMismatches;
    @JsonIgnore
    private double matchShare;
    @JsonIgnore
    private int reinvocations;
    @JsonProperty("rematches")
    private int rematches;
    @JsonProperty("remismatches")
    private int remismatches;
    @JsonIgnore
    private double reinvocationShare;
    @JsonIgnore
    private long totalNanoTime;
    @JsonProperty("ruleReports")
    private List<RuleReport> ruleReports;

    @JsonCreator
    protected ProfilingReportMixin(
        @JsonProperty("runs") final int totalRuns,
        @JsonProperty("matches") final int totalMatches,
        @JsonProperty("mismatches") final int totalMismatches,
        @JsonProperty("rematches") final int rematches,
        @JsonProperty("remismatches") final int remismatches,
        @JsonProperty("totalNanoTime") final int totalNanoTime,
        @JsonProperty("ruleReports") final List<RuleReport> ruleReports
    )
    {
    }
}

Since there is no "bean constructor" I decided to go the @JsonCreator way, obviously.

I create the Module, register it, no problem... Except that it fails when attempting to deserialize a sample JSON:

Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class org.parboiled.parserunners.ProfilingParseRunner$Report]: can not instantiate from JSON object (need to add/enable type information?)
 at [Source: java.io.BufferedInputStream@b41b571; line: 2, column: 5]
    at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:164)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1078)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:268)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:124)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2993)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2144)
    at com.github.parboiled1.grappa.assertions.mixins.ProfilingReportMixin.main(ProfilingReportMixin.java:70)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

I don't really understand; I did annotate the mixin class' constructor with @JsonCreator and it has always worked for me so far for "normal" deserialization (it is my first time trying a mixin).

Is this a bug in Jackson or am I doing something wrong?


edit: the main:

public static void main(final String... args)
    throws IOException
{
    final ObjectMapper mapper = new ObjectMapper()
        .configure(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true);
    mapper.registerModule(GrappaModule.INSTANCE);

    final Closer closer = Closer.create();
    final InputStream in;

    try {
        in = closer.register(ProfilingReportMixin.class.
            getResourceAsStream("/profilingReports/test.json"));
        if (in == null)
            throw new IOException("resource not found");
        final ProfilingParseRunner.Report report
            = mapper.readValue(in, ProfilingParseRunner.Report.class);
        mapper.writerWithDefaultPrettyPrinter()
            .writeValue(System.out, report);
    } finally {
        closer.close();
    }
}

and the Module:

public final class GrappaModule
    extends SimpleModule
{
    private static final Version VERSION = new Version(1, 0, 0,
        "beta.5-SNAPSHOT", "com.github.parboiled1", "grappa");

    public static final Module INSTANCE = new GrappaModule();

    private GrappaModule()
    {
        super("grappa", VERSION);
    }

    @Override
    public void setupModule(final SetupContext context)
    {
        context.setMixInAnnotations(ProfilingParseRunner.RuleReport.class,
            RuleReportMixin.class);
        context.setMixInAnnotations(ProfilingParseRunner.Report.class,
            ProfilingReportMixin.class);
    }
}
Was it helpful?

Solution

Ensure that the ctor signature on your mixin class matches the ctor signature on your target class. Your target class ctor has totalNanoTime as a long, but your mixin ctor has totalNanoTime as an int.

░░░░░░░░░▄░░░░░░░░░░░░░░▄░░░░
░░░░░░░░▌▒█░░░░░░░░░░░▄▀▒▌░░░
░░░░░░░░▌▒▒█░░░░░░░░▄▀▒▒▒▐░░░
░░░░░░░▐▄▀▒▒▀▀▀▀▄▄▄▀▒▒▒▒▒▐░░░
░░░░░▄▄▀▒░▒▒▒▒▒▒▒▒▒█▒▒▄█▒▐░░░
░░░▄▀▒▒▒░░░▒▒▒░░░▒▒▒▀██▀▒▌░░░ 
░░▐▒▒▒▄▄▒▒▒▒░░░▒▒▒▒▒▒▒▀▄▒▒▌░░
░░▌░░▌█▀▒▒▒▒▒▄▀█▄▒▒▒▒▒▒▒█▒▐░░
░▐░░░▒▒▒▒▒▒▒▒▌██▀▒▒░░░▒▒▒▀▄▌░
░▌░▒▄██▄▒▒▒▒▒▒▒▒▒░░░░░░▒▒▒▒▌░
▀▒▀▐▄█▄█▌▄░▀▒▒░░░░░░░░░░▒▒▒▐░
▐▒▒▐▀▐▀▒░▄▄▒▄▒▒▒▒▒▒░▒░▒░▒▒▒▒▌
▐▒▒▒▀▀▄▄▒▒▒▄▒▒▒▒▒▒▒▒░▒░▒░▒▒▐░
░▌▒▒▒▒▒▒▀▀▀▒▒▒▒▒▒░▒░▒░▒░▒▒▒▌░
░▐▒▒▒▒▒▒▒▒▒▒▒▒▒▒░▒░▒░▒▒▄▒▒▐░░
░░▀▄▒▒▒▒▒▒▒▒▒▒▒░▒░▒░▒▄▒▒▒▒▌░░
░░░░▀▄▒▒▒▒▒▒▒▒▒▒▄▄▄▀▒▒▒▒▄▀░░░
░░░░░░▀▄▄▄▄▄▄▀▀▀▒▒▒▒▒▄▄▀░░░░░
░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▀▀░░░░░░░░

such amaze.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top