1
1
package com .fasterxml .jackson .dataformat .avro .schema ;
2
2
3
+ import java .util .ArrayList ;
4
+ import java .util .List ;
5
+
6
+ import org .apache .avro .Schema ;
7
+ import org .apache .avro .reflect .AvroMeta ;
8
+ import org .apache .avro .reflect .AvroSchema ;
9
+
3
10
import com .fasterxml .jackson .databind .*;
4
11
import com .fasterxml .jackson .databind .jsonFormatVisitors .JsonFormatVisitable ;
5
12
import com .fasterxml .jackson .databind .jsonFormatVisitors .JsonObjectFormatVisitor ;
6
13
import com .fasterxml .jackson .databind .ser .BeanPropertyWriter ;
7
14
import com .fasterxml .jackson .dataformat .avro .AvroFixedSize ;
8
- import org .apache .avro .Schema ;
9
-
10
- import java .util .ArrayList ;
11
- import java .util .List ;
12
15
13
16
public class RecordVisitor
14
17
extends JsonObjectFormatVisitor .Base
@@ -18,6 +21,12 @@ public class RecordVisitor
18
21
19
22
protected final DefinedSchemas _schemas ;
20
23
24
+ /**
25
+ * Tracks if the schema for this record has been overridden (by an annotation or other means), and calls to the {@code property} and
26
+ * {@code optionalProperty} methods should be ignored.
27
+ */
28
+ protected final boolean _overridden ;
29
+
21
30
protected Schema _avroSchema ;
22
31
23
32
protected List <Schema .Field > _fields = new ArrayList <Schema .Field >();
@@ -27,16 +36,29 @@ public RecordVisitor(SerializerProvider p, JavaType type, DefinedSchemas schemas
27
36
super (p );
28
37
_type = type ;
29
38
_schemas = schemas ;
30
- _avroSchema = Schema .createRecord (AvroSchemaHelper .getName (type ),
31
- "Schema for " +type .toCanonical (),
32
- AvroSchemaHelper .getNamespace (type ), false );
39
+ // Check if the schema for this record is overridden
40
+ BeanDescription bean = getProvider ().getConfig ().introspectDirectClassAnnotations (_type );
41
+ AvroSchema ann = bean .getClassInfo ().getAnnotation (AvroSchema .class );
42
+ if (ann != null ) {
43
+ _avroSchema = AvroSchemaHelper .parseJsonSchema (ann .value ());
44
+ _overridden = true ;
45
+ } else {
46
+ _avroSchema = AvroSchemaHelper .initializeRecordSchema (bean );
47
+ _overridden = false ;
48
+ AvroMeta meta = bean .getClassInfo ().getAnnotation (AvroMeta .class );
49
+ if (meta != null ) {
50
+ _avroSchema .addProp (meta .key (), meta .value ());
51
+ }
52
+ }
33
53
schemas .addSchema (type , _avroSchema );
34
54
}
35
55
36
56
@ Override
37
57
public Schema builtAvroSchema () {
38
- // Assumption now is that we are done, so let's assign fields
39
- _avroSchema .setFields (_fields );
58
+ if (!_overridden ) {
59
+ // Assumption now is that we are done, so let's assign fields
60
+ _avroSchema .setFields (_fields );
61
+ }
40
62
return _avroSchema ;
41
63
}
42
64
@@ -49,14 +71,19 @@ public Schema builtAvroSchema() {
49
71
@ Override
50
72
public void property (BeanProperty writer ) throws JsonMappingException
51
73
{
52
- Schema schema = schemaForWriter (writer );
53
- _fields .add (new Schema .Field (writer .getName (), schema , null , null ));
74
+ if (_overridden ) {
75
+ return ;
76
+ }
77
+ _fields .add (schemaFieldForWriter (writer , false ));
54
78
}
55
79
56
80
@ Override
57
81
public void property (String name , JsonFormatVisitable handler ,
58
82
JavaType type ) throws JsonMappingException
59
83
{
84
+ if (_overridden ) {
85
+ return ;
86
+ }
60
87
VisitorFormatWrapperImpl wrapper = new VisitorFormatWrapperImpl (_schemas , getProvider ());
61
88
handler .acceptJsonFormatVisitor (wrapper , type );
62
89
Schema schema = wrapper .getAvroSchema ();
@@ -65,21 +92,19 @@ public void property(String name, JsonFormatVisitable handler,
65
92
66
93
@ Override
67
94
public void optionalProperty (BeanProperty writer ) throws JsonMappingException {
68
- Schema schema = schemaForWriter (writer );
69
- /* 23-Nov-2012, tatu: Actually let's also assume that primitive type values
70
- * are required, as Jackson does not distinguish whether optional has been
71
- * defined, or is merely the default setting.
72
- */
73
- if (!writer .getType ().isPrimitive ()) {
74
- schema = AvroSchemaHelper .unionWithNull (schema );
95
+ if (_overridden ) {
96
+ return ;
75
97
}
76
- _fields .add (new Schema . Field (writer . getName (), schema , null , null ));
98
+ _fields .add (schemaFieldForWriter (writer , true ));
77
99
}
78
100
79
101
@ Override
80
102
public void optionalProperty (String name , JsonFormatVisitable handler ,
81
103
JavaType type ) throws JsonMappingException
82
104
{
105
+ if (_overridden ) {
106
+ return ;
107
+ }
83
108
VisitorFormatWrapperImpl wrapper = new VisitorFormatWrapperImpl (_schemas , getProvider ());
84
109
handler .acceptJsonFormatVisitor (wrapper , type );
85
110
Schema schema = wrapper .getAvroSchema ();
@@ -95,29 +120,53 @@ public void optionalProperty(String name, JsonFormatVisitable handler,
95
120
/**********************************************************************
96
121
*/
97
122
98
- protected Schema schemaForWriter (BeanProperty prop ) throws JsonMappingException
123
+ protected Schema . Field schemaFieldForWriter (BeanProperty prop , boolean optional ) throws JsonMappingException
99
124
{
100
- AvroFixedSize fixedSize = prop .getAnnotation (AvroFixedSize .class );
101
- if (fixedSize != null ) {
102
- return Schema .createFixed (fixedSize .typeName (), null , fixedSize .typeNamespace (), fixedSize .size ());
103
- }
125
+ Schema writerSchema ;
126
+ // Check if schema for property is overridden
127
+ AvroSchema schemaOverride = prop .getAnnotation (AvroSchema .class );
128
+ if (schemaOverride != null ) {
129
+ Schema .Parser parser = new Schema .Parser ();
130
+ writerSchema = parser .parse (schemaOverride .value ());
131
+ } else {
132
+ AvroFixedSize fixedSize = prop .getAnnotation (AvroFixedSize .class );
133
+ if (fixedSize != null ) {
134
+ writerSchema = Schema .createFixed (fixedSize .typeName (), null , fixedSize .typeNamespace (), fixedSize .size ());
135
+ } else {
136
+ JsonSerializer <?> ser = null ;
104
137
105
- JsonSerializer <?> ser = null ;
138
+ // 23-Nov-2012, tatu: Ideally shouldn't need to do this but...
139
+ if (prop instanceof BeanPropertyWriter ) {
140
+ BeanPropertyWriter bpw = (BeanPropertyWriter ) prop ;
141
+ ser = bpw .getSerializer ();
142
+ }
143
+ final SerializerProvider prov = getProvider ();
144
+ if (ser == null ) {
145
+ if (prov == null ) {
146
+ throw JsonMappingException .from (prov , "SerializerProvider missing for RecordVisitor" );
147
+ }
148
+ ser = prov .findValueSerializer (prop .getType (), prop );
149
+ }
150
+ VisitorFormatWrapperImpl visitor = new VisitorFormatWrapperImpl (_schemas , prov );
151
+ ser .acceptJsonFormatVisitor (visitor , prop .getType ());
152
+ writerSchema = visitor .getAvroSchema ();
153
+ }
106
154
107
- // 23-Nov-2012, tatu: Ideally shouldn't need to do this but...
108
- if (prop instanceof BeanPropertyWriter ) {
109
- BeanPropertyWriter bpw = (BeanPropertyWriter ) prop ;
110
- ser = bpw .getSerializer ();
111
- }
112
- final SerializerProvider prov = getProvider ();
113
- if (ser == null ) {
114
- if (prov == null ) {
115
- throw JsonMappingException .from (prov , "SerializerProvider missing for RecordVisitor" );
155
+ /* 23-Nov-2012, tatu: Actually let's also assume that primitive type values
156
+ * are required, as Jackson does not distinguish whether optional has been
157
+ * defined, or is merely the default setting.
158
+ */
159
+ if (optional && !prop .getType ().isPrimitive ()) {
160
+ writerSchema = AvroSchemaHelper .unionWithNull (writerSchema );
116
161
}
117
- ser = prov .findValueSerializer (prop .getType (), prop );
118
162
}
119
- VisitorFormatWrapperImpl visitor = new VisitorFormatWrapperImpl (_schemas , prov );
120
- ser .acceptJsonFormatVisitor (visitor , prop .getType ());
121
- return visitor .getAvroSchema ();
163
+ Schema .Field field = new Schema .Field (prop .getName (), writerSchema , prop .getMetadata ().getDescription (), null );
164
+
165
+ AvroMeta meta = prop .getAnnotation (AvroMeta .class );
166
+ if (meta != null ) {
167
+ field .addProp (meta .key (), meta .value ());
168
+ }
169
+
170
+ return field ;
122
171
}
123
172
}
0 commit comments