34

I have an Item class. There's an itemType field inside of that class which is of type ItemType.

roughly, something like this.

class Item
{
   int id;
   ItemType itemType;
}

class ItemType
{
   String name;
   int somethingElse;
}

When I am serializing an object of type Item using Jackson ObjectMapper, it serializes the object ItemType as a sub-object. Which is expected, but not what I want.

{
  "id": 4,  
  "itemType": {
    "name": "Coupon",
    "somethingElse": 1
  }
}

What I would like to do is to show the itemType's name field instead when serialized.

Something like below.

{
  "id": 4,  
  "itemType": "Coupon"
}

Is there anyway to instruct Jackson to do so?

Ranhiru Jude Cooray
  • 19,542
  • 20
  • 83
  • 128

5 Answers5

37

Check out @JsonValue annotation.

EDIT: like this:

class ItemType
{
  @JsonValue
  public String name;

  public int somethingElse;
}
StaxMan
  • 113,358
  • 34
  • 211
  • 239
  • 2
    Question was "How to instruct Jackson to serialize a field inside an Object instead of the Object it self?" and that is done by annotating said field with `@JsonValue`. – StaxMan Jun 15 '12 at 18:51
  • 1
    This is the best answer to the original question though pingw33n's answer actually helps my situation which was slightly different than the original question here – Kirby Nov 04 '14 at 17:30
  • `@JsonValue` cannot be used to annotate a field (at least, not in version 2.6.7). It has `@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})` – Gili Oct 20 '16 at 20:44
  • 1
    It can be used to annotate a field in version 2.9 and up – John Calcote Mar 23 '18 at 19:02
  • For the super lazy (which is probably myself googling this SO answer in the future): Javadocs say _"Marker annotation that indicates that the value of annotated accessor (either field or "getter" method [a method with non-void return type, no args]) is to be used as the single value to serialize for the instance"_ http://fasterxml.github.io/jackson-annotations/javadoc/2.9/com/fasterxml/jackson/annotation/JsonValue.html – broc.seib May 01 '18 at 19:29
23

You need to create and use a custom serializer.

public class ItemTypeSerializer extends JsonSerializer<ItemType> 
{
    @Override
    public void serialize(ItemType value, JsonGenerator jgen, 
                    SerializerProvider provider) 
                    throws IOException, JsonProcessingException 
    {
        jgen.writeString(value.name);
    }

}

@JsonSerialize(using = ItemTypeSerializer.class)
class ItemType
{
    String name;
    int somethingElse;
}
pingw33n
  • 12,292
  • 2
  • 37
  • 38
  • This works. And for sake of completeness, a related possibility is to make `ItemType` implement `JsonSerializable` (method "serialize()"). – StaxMan Nov 07 '14 at 22:07
  • I don't know why I can't declare the Serializer as an inner Class, it keeps giving me an error. – Evan Hu Oct 21 '16 at 08:40
4

As OP only wants to serialize one field, you could also use the @JsonIdentityInfo and @JsonIdentityReference annotations:

class Item {
    int id;
    @JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="name")
    @JsonIdentityReference(alwaysAsId=true)
    ItemType itemType;
}

For more info, see How to serialize only the ID of a child with Jackson.

Community
  • 1
  • 1
Jacob van Lingen
  • 8,989
  • 7
  • 48
  • 78
2

Perhaps a quick workaround is to add an extra getter on Item to return ItemType.name, and mark ItemType getter with @JsonIgnore?

maksimov
  • 5,792
  • 1
  • 30
  • 38
2

To return simple string, you can use default ToStringSerializer without define any extra classes. But you have to define toString() method return this value only.

@JsonSerialize(using = ToStringSerializer.class)
class ItemType
{
   String name;
   int somethingElse;
   public String toString(){ return this.name;}
}
Chenhai-胡晨海
  • 1,315
  • 9
  • 7