JsonMappingException: Not a map, not an array or not an enum
Asked Answered
T

3

8

I am working on a rest api application and i have some problems with the code. I want to return an object that extends avro schema and adds HATEOAS links to the response. I did some investigation and as it turns out i need custom serializer for object.

Part of code that is problematic is:

@JsonValue
public String serialize() throws JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();
    return mapper.writeValueAsString(this);
}

This returns

Could not write JSON: Not an enum.

The current object is an extend of avro schema. I also tried:

@JsonValue
public String serialize() throws JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();
    return mapper.writeValueAsString(getUserData());
}

It returns:

Could not write JSON: Not an array

Where user data is an actual avro object. I dont understand what do these error mean. Can someone explain? Also, is there a better way to return an avro object combined with other parameters?

Thanks

EDIT:

Here is the full example:

public class PaginatedUserData extends UserDataAvro {
    @JsonValue
    public String serialize() throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        HashMap<String, String> map = new HashMap<>();
        map.put("test", "5");
        return mapper.writeValueAsString(map);
    }
}

Returns:

Could not write JSON: Not an array

Tore answered 16/3, 2020 at 10:9 Comment(0)
K
13

I had a similar problem, and solved it with Jackson-Mixin (from https://mcmap.net/q/143554/-how-can-i-tell-jackson-to-ignore-a-property-for-which-i-don-39-t-have-control-over-the-source-code ). Avro seems to generate Avro specifc Getter Methods which should always be ignored during Jackson serialization.

public abstract class JacksonIgnoreAvroPropertiesMixIn {

  @JsonIgnore
  public abstract org.apache.avro.Schema getSchema();

  @JsonIgnore
  public abstract org.apache.avro.specific.SpecificData getSpecificData();
}

And on the ObjectMapper than:

objectMapper.addMixIn(
        org.apache.avro.specific.SpecificRecord.class, // Interface implemented by all generated Avro-Classes
        JacksonIgnoreAvroPropertiesMixIn.class);
Kalisz answered 29/3, 2021 at 10:11 Comment(4)
Thanks for your answer. Where do you get objectMapper from?Bernardabernardi
If you have the spring-boot-starter-web dependency, it should be already in your Spring-Context. Otherwise, just call the constructor: new com.fasterxml.jackson.databind.ObjectMapper()Kalisz
@HaraldBrabenetz this helped me tremendous! Any idea how I could still use something like JsonInclude.Include.NON_NULL with this? The response is removing the null values.Warrantable
@RenatoGama. More than likely, it is "import com.fasterxml.jackson.databind.ObjectMapper;" ..Stollings
A
1

Jackson can be problematic sometimes. These error mean that spring boot expects data different than in your result.

You should return object that has an avro schema as the property, like so:

class UserResponse extends ResourceSupport {
  UserData userData;
  public void getUserData() { ... }
}

Then you return this in controller:

return new UserResponse();

If this still does not work for you, i suggest you use Gson. For your application it would look something like this:

Gson gson = new Gson();
UserResponse data = new UserResponse();

String json = gson.toJson(data.getUserData());
Albright answered 18/3, 2020 at 17:5 Comment(0)
B
1

I had the same problem when serializing a Kafka message out of an @AvroGenerated class (Kotlin with Micronaut framework). What worked for me was making sure to use an Avro serializer, like this:

    override fun getProperties() = mutableMapOf(
        "kafka.bootstrap.servers" to kafka.bootstrapServers,
        "kafka.producers.default.value.serializer" to KafkaAvroSerializer::class.java.name,
        "kafka.producers.default.key.serializer" to StringSerializer::class.java.name,
        "kafka.producers.default.schema.registry.url" to "mock://my-scope-name",
        "kafka.consumers.default.schema.registry.url" to "mock://my-scope-name",
        "kafka.consumers.default." + KafkaAvroDeserializerConfig.SPECIFIC_AVRO_READER_CONFIG to "true"
    )
Bernardabernardi answered 24/8, 2021 at 14:42 Comment(1)
may be something like this: #39350233Soothsay

© 2022 - 2025 — McMap. All rights reserved.