1 package com.fasterxml.jackson.databind.ser.std;
2
3 import java.io.IOException;
4 import java.lang.reflect.Type;
5
6 import com.fasterxml.jackson.annotation.JsonFormat;
7 import com.fasterxml.jackson.core.JsonGenerator;
8 import com.fasterxml.jackson.core.JsonParser.NumberType;
9 import com.fasterxml.jackson.databind.BeanProperty;
10 import com.fasterxml.jackson.databind.JavaType;
11 import com.fasterxml.jackson.databind.JsonMappingException;
12 import com.fasterxml.jackson.databind.JsonNode;
13 import com.fasterxml.jackson.databind.JsonSerializer;
14 import com.fasterxml.jackson.databind.SerializerProvider;
15 import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
16 import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
17 import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
18 import com.fasterxml.jackson.databind.ser.ContextualSerializer;
19
20 /**
21  * Serializer used for primitive boolean, as well as java.util.Boolean
22  * wrapper type.
23  *<p>
24  * Since this is one of "natural" (aka "native") types, no type information is ever
25  * included on serialization (unlike for most other scalar types)
26  */

27 @JacksonStdImpl
28 public final class BooleanSerializer
29 //In 2.9, removed use of intermediate type `NonTypedScalarSerializerBase`
30     extends StdScalarSerializer<Object>
31     implements ContextualSerializer
32 {
33     private static final long serialVersionUID = 1L;
34
35     /**
36      * Whether type serialized is primitive (boolean) or wrapper
37      * (java.lang.Boolean); if true, former, if false, latter.
38      */

39     protected final boolean _forPrimitive;
40
41     public BooleanSerializer(boolean forPrimitive) {
42         super(forPrimitive ? Boolean.TYPE : Boolean.classfalse);
43         _forPrimitive = forPrimitive;
44     }
45
46     @Override
47     public JsonSerializer<?> createContextual(SerializerProvider serializers,
48             BeanProperty property) throws JsonMappingException
49     {
50         JsonFormat.Value format = findFormatOverrides(serializers,
51                 property, Boolean.class);
52         if (format != null) {
53             JsonFormat.Shape shape = format.getShape();
54             if (shape.isNumeric()) {
55                 return new AsNumber(_forPrimitive);
56             }
57         }
58         return this;
59     }
60
61     @Override
62     public void serialize(Object value, JsonGenerator g, SerializerProvider provider) throws IOException {
63         g.writeBoolean(Boolean.TRUE.equals(value));
64     }
65
66     @Override
67     public final void serializeWithType(Object value, JsonGenerator g, SerializerProvider provider,
68             TypeSerializer typeSer) throws IOException
69     {
70         g.writeBoolean(Boolean.TRUE.equals(value));
71     }
72
73     @Override
74     public JsonNode getSchema(SerializerProvider provider, Type typeHint) {
75         return createSchemaNode("boolean", !_forPrimitive);
76     }
77
78     @Override
79     public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint) throws JsonMappingException {
80         visitor.expectBooleanFormat(typeHint);
81     }
82
83     /**
84      * Alternate implementation that is used when values are to be serialized
85      * as numbers <code>0</code> (false) or <code>1</code> (true).
86      * 
87      * @since 2.9
88      */

89     final static class AsNumber
90         extends StdScalarSerializer<Object>
91         implements ContextualSerializer
92     {
93         private static final long serialVersionUID = 1L;
94
95         /**
96          * Whether type serialized is primitive (boolean) or wrapper
97          * (java.lang.Boolean); if true, former, if false, latter.
98          */

99         protected final boolean _forPrimitive;
100
101         public AsNumber(boolean forPrimitive) {
102             super(forPrimitive ? Boolean.TYPE : Boolean.classfalse);
103             _forPrimitive = forPrimitive;
104         }
105
106         @Override
107         public void serialize(Object value, JsonGenerator g, SerializerProvider provider) throws IOException {
108             g.writeNumber((Boolean.FALSE.equals(value)) ? 0 : 1);
109         }
110
111         @Override
112         public final void serializeWithType(Object value, JsonGenerator g, SerializerProvider provider,
113                 TypeSerializer typeSer) throws IOException
114         {
115             // 27-Mar-2017, tatu: Actually here we CAN NOT serialize as number without type,
116             //    since with natural types that would map to number, not boolean. So choice
117             //    comes to between either add type id, or serialize as boolean. Choose
118             //    latter at this point
119             g.writeBoolean(Boolean.TRUE.equals(value));
120         }
121
122         @Override
123         public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint) throws JsonMappingException {
124             // 27-Mar-2017, tatu: As usual, bit tricky but... seems like we should call
125             //    visitor for actual representation
126             visitIntFormat(visitor, typeHint, NumberType.INT);
127         }
128
129         @Override
130         public JsonSerializer<?> createContextual(SerializerProvider serializers,
131                 BeanProperty property) throws JsonMappingException
132         {
133             JsonFormat.Value format = findFormatOverrides(serializers,
134                     property, Boolean.class);
135             if (format != null) {
136                 JsonFormat.Shape shape = format.getShape();
137                 if (!shape.isNumeric()) {
138                     return new BooleanSerializer(_forPrimitive);
139                 }
140             }
141             return this;
142         }
143     }
144 }
145