How to unwrap custom serialized objects from "content" key with Jackon & Spring Boot

Viewed 399

I have customly serialized my object which is represented by this class:

public class Product {
    private Long id;
    private String name;
    private Unit defaultUnit;
    private Section section;
}

Serialization:

@Override
public void serialize(Product product, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
    jsonGenerator.writeNumberField("id", product.getId());
    jsonGenerator.writeStringField("name", product.getName());
    jsonGenerator.writeStringField("defaultUnit", product.getDefaultUnit().toString());
    jsonGenerator.writeObjectField("section", product.getSection());
}

However this produces an error which as I understand means that the default serializer has created a key and I have to provide it with a value:

Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Can not write a field name, expecting a value; nested exception is com.fasterxml.jackson.core.JsonGenerationException: Can not write a field name, expecting a value]

Now it is obvious that the solution is to wrap the fields adding

    jsonGenerator.writeStartObject();
    jsonGenerator.writeEndObject();

This however results in generating entity wrapped in "content" object:

"content": {
  "id": 1,
  "name": "Product",
  "defaultUnit": "Unit",
  "section": {
    "name": "Section"
  }
}

My question is whether it is possible to write the entity unwrapped that is without the "content" key.

The following is all the code associated with Product: Product.java

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@RequiredArgsConstructor
@JsonDeserialize(using = ProductDeserializer.class)
@JsonSerialize(using = ProductSerializer.class)
public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NonNull
    private String name;

    @ManyToOne
    @NonNull
    private Unit defaultUnit;

    @ManyToOne
    @NonNull
    private Section section;
}

ProductExcerpt.java

@Projection(name = "productExcerpt", types = {Product.class})
public interface ProductExcerpt {
    String getName();
    @Value("#{target.defaultUnit.toString()}")
    String getDefaultUnit();
    SectionExcerpt getSection();
}

ProductRepository.java

@RepositoryRestResource(excerptProjection = ProductExcerpt.class)
@CrossOrigin
public interface ProductRepository extends JpaRepository<Product, Long> {
}

ProductSerializer.java

public class ProductSerializer extends StdSerializer<Product> {

    ProductSerializer(){
        super(Product.class);
    }

    @Override
    public void serialize(Product product, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeStartObject();
        jsonGenerator.writeNumberField("id", product.getId());
        jsonGenerator.writeStringField("name", product.getName());
        jsonGenerator.writeStringField("defaultUnit", product.getDefaultUnit().toString());
        jsonGenerator.writeObjectField("section", product.getSection());
        jsonGenerator.writeEndObject();
    }
}

There is also ProductDeserializer class however I think that it is irrevelant in this case. I do not have a Controller configured beacause as far as I am concerned there is no need while using spring-data-rest.

0 Answers
Related