dataMetaJacksonSer 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: aaf9ff84148a45b237fedbc3145b843bc1877a38
4
+ data.tar.gz: b902109105871f7aafc26ac1a29ea6aa48bd3ff8
5
+ SHA512:
6
+ metadata.gz: fd5412944ff51009a98f019ae3755d9aa8d1d54d2170d66f1ad608d3fabbb6b66c42095a19f271e6ebd3b95eccae72051c5e57a2c6b52b42a96e8b4cf5192141
7
+ data.tar.gz: 75708f115d9fb0d0b11c37a6151ccd92f85a74bc8b2630ff5b1fea36723298672b0e63af823eec74daad716bdba7f214ca094af1e63baec6aab03d00923c87b1
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --title "DataMeta JSON (de)serialization with Jackson" -r README.md --charset UTF-8 lib/**/* - README.md
data/History.md ADDED
@@ -0,0 +1,5 @@
1
+ # `dataMetaJacksonSer` Release history:
2
+
3
+ ## `1.0.0` released `2017-04-04 Tue` by [`mub`](https://github.com/mub)
4
+ * 1 major enhancement:
5
+ * Initial release
data/PostInstall.txt ADDED
@@ -0,0 +1 @@
1
+ No special steps
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # `dataMetaJacksonSer` gem
2
+
3
+ JSON (de)serialization generation from [DataMeta DOM](https://github.com/eBayDataMeta/DataMeta-gems/tree/master/meta/core/dom) sources
4
+ using FasterXML Jackson.
5
+
6
+ References to this gem's:
7
+
8
+ * [Source](https://github.com/eBayDataMeta/DataMeta-gems/tree/master/meta/ser/jackson/fasterxml)
9
+
10
+
11
+ ## DESCRIPTION:
12
+
13
+ See the [DataMeta Project Documentation Repository](https://github.com/eBayDataMeta/DataMeta)
14
+
15
+ ## FEATURES:
16
+
17
+ Generates (de)serializers to/from JSON using FasterXML Jackson.
18
+
19
+ ## SYNOPSIS:
20
+
21
+ To generate Byte Array serializers in Java, including Hadoop Writables for the DataMeta model, run:
22
+
23
+ dataMetaJacksonSerGen.rb <DataMeta DOM source> <Target Directory>
24
+
25
+ ## REQUIREMENTS:
26
+
27
+ * No special requirements
28
+
29
+ ## INSTALL:
30
+
31
+ gem install dataMetaJacksonSer
32
+
33
+ ## LICENSE:
34
+
35
+ [Apache v 2.0](https://github.com/eBayDataMeta/DataMeta/blob/master/LICENSE.md)
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ %w(yard rdoc/task rake/testtask ./lib/dataMetaJacksonSer ./lib/dataMetaJacksonSer/util).each{ |r| require r}
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << 'test'
5
+ end
6
+
7
+ desc 'Regen RDocs'
8
+ task :default => :docs
9
+
10
+ YARD::Rake::YardocTask.new('docs') {|r|
11
+ r.stats_options = ['--list-undoc']
12
+ }
13
+
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ %w( dataMetaDom dataMetaJacksonSer ).each(&method(:require))
3
+
4
+ @source, @target = ARGV
5
+ DataMetaJacksonSer::helpDataMetaJacksonSerGen __FILE__ unless @source && @target
6
+ DataMetaJacksonSer::helpDataMetaJacksonSerGen(__FILE__, "DataMeta DOM source #{@source} is not a file") unless File.file?(@source)
7
+ DataMetaJacksonSer::helpDataMetaJacksonSerGen(__FILE__, "Jacksonables destination directory #{@target} is not a dir") unless File.directory?(@target)
8
+
9
+ @parser = DataMetaDom::Model.new
10
+ begin
11
+ @parser.parse(@source, options={autoVerNs: true})
12
+ DataMetaJacksonSer::genJacksonables(@parser, @target)
13
+ puts "Jackson serialization classes written to #{@target}. Done."
14
+ rescue Exception => e
15
+ $stderr.puts "ERROR #{e.message}; #{@parser.diagn}"
16
+ $stderr.puts e.backtrace.inspect
17
+ end
@@ -0,0 +1,133 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
2
+
3
+ require 'set'
4
+ require 'logger'
5
+
6
+ module DataMetaJacksonSer
7
+
8
+ =begin rdoc
9
+ A holder for a read renderer and a write renderer, those come in pairs that have to be consistent so the
10
+ data is read and written uniformly.
11
+ =end
12
+ class RwHolder
13
+ =begin rdoc
14
+ Read renderer.
15
+ =end
16
+ attr_reader :r
17
+ =begin rdoc
18
+ Write renderer.
19
+ =end
20
+ attr_reader :w
21
+ =begin rdoc
22
+ Creates a new HDFS Reade and Write renderers pair.
23
+ =end
24
+ def initialize(readRenderer, writeRenderer); @r = readRenderer; @w = writeRenderer end
25
+ end
26
+
27
+ =begin rdoc
28
+ Rendering context with rendering-related properties and settings.
29
+ =end
30
+ class RendCtx
31
+
32
+ =begin rdoc
33
+ DataMeta DOM Model on the context.
34
+ =end
35
+ attr_accessor :model
36
+ =begin rdoc
37
+ Record currently worked on.
38
+ =end
39
+ attr_accessor :rec
40
+
41
+ =begin rdoc
42
+ Set of imports if any, each as symbol.
43
+ =end
44
+ attr_accessor :imps
45
+
46
+ =begin rdoc
47
+ Java package.
48
+ =end
49
+ attr_accessor :pckg
50
+ =begin rdoc
51
+ Base name of the type, without a namespace.
52
+ =end
53
+ attr_accessor :baseName
54
+ =begin rdoc
55
+ The data type of the entity on the context.
56
+ =end
57
+ attr_accessor :refType
58
+ =begin rdoc
59
+ Field currently on the context.
60
+ =end
61
+ attr_reader :fld
62
+
63
+ =begin rdoc
64
+ Creates a new context.
65
+ =end
66
+ def initialize; @imps = Set.new end
67
+
68
+ =begin rdoc
69
+ Setter for the field on the context, the field currently worked on.
70
+ =end
71
+ def fld=(val); @fld = val end
72
+
73
+ =begin rdoc
74
+ Initialize the context with the model, the record, the package and the basename.
75
+ Returns self for call chaining.
76
+ =end
77
+ def init(model, rec, pckg, baseName); @model = model; @rec = rec; @pckg = pckg; @baseName = baseName; self end
78
+
79
+ =begin rdoc
80
+ Add an import to the context, returns self for call chaining.
81
+ =end
82
+ def <<(import)
83
+ @imps << import.to_sym if import
84
+ self
85
+ end
86
+
87
+ =begin rdoc
88
+ Formats imports into Java source, sorted.
89
+ =end
90
+ def importsText
91
+ @imps.to_a.map{|k| "import #{k};"}.sort.join("\n")
92
+ end
93
+
94
+ =begin rdoc
95
+ Determines if the refType is a DataMetaDom::Mapping.
96
+ =end
97
+ def isMapping
98
+ @refType.kind_of?(DataMetaDom::Mapping) && !@refType.kind_of?(DataMetaDom::BitSet)
99
+ end
100
+
101
+ # Effective field type
102
+ def fType
103
+ isMapping ? @refType.fromT : @fld.dataType
104
+ end
105
+
106
+ # Readwrap
107
+ def rw
108
+ isMapping ? lambda{|t| "new #{condenseType(@fld.dataType.type, self)}(#{t})"} : lambda{|t| t}
109
+ end
110
+
111
+ =begin rdoc
112
+ Getter name for the current field, if the type is Mapping, includes <tt>.getKey()</tt> too.
113
+ =end
114
+ def valGetter
115
+ "#{DataMetaDom.getterName(@fld)}" + ( isMapping ? '.getKey' : '')
116
+ end
117
+ end # RendCtx
118
+
119
+ =begin rdoc
120
+ Builds a class name for a InOutable.
121
+ =end
122
+ def jsonableClassName(baseName); "#{baseName}_JSONable" end
123
+
124
+ def mapsNotSupported(fld)
125
+ raise ArgumentError, "Field #{fld.name}: maps are not currently supported on JSON serialization layer"
126
+ end
127
+
128
+ def aggrNotSupported(fld, forWhat)
129
+ raise ArgumentError, "Field #{fld.name}: aggregate types are not supported for #{forWhat} on JSON serialization layer"
130
+ end
131
+
132
+ module_function :jsonableClassName, :mapsNotSupported, :aggrNotSupported
133
+ end
@@ -0,0 +1,356 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
2
+
3
+ # Definition for generating Plain Old Java Objects (POJOs)
4
+ %w(fileutils dataMetaDom dataMetaDom/pojo dataMetaDom/enum dataMetaDom/record dataMetaDom/help dataMetaDom/util).each(&method(:require))
5
+ require 'set'
6
+ require 'dataMetaJacksonSer/util'
7
+
8
+ =begin rdoc
9
+ Serialization artifacts generation such as Hadoop Writables etc.
10
+
11
+ TODO this isn't a bad way, but beter use templating next time such as {ERB}[http://ruby-doc.org/stdlib-1.9.3/libdoc/erb/rdoc/ERB.html].
12
+
13
+ For command line details either check the new method's source or the README.rdoc file, the usage section.
14
+ =end
15
+ module DataMetaJacksonSer
16
+ # Current version
17
+ VERSION = '1.0.0'
18
+ include DataMetaDom, DataMetaDom::PojoLexer
19
+
20
+ =begin rdoc
21
+ HDFS Reader and Writer for textual Java types such as String.
22
+ =end
23
+ TEXT_RW_METHODS = RwHolder.new(
24
+ lambda{|ctx|
25
+ ctx.fld.aggr ? ctx.rw.call("read#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}String(in)") : ctx.rw.call('readText(in)')
26
+ },
27
+ lambda{|ctx|
28
+ ctx.fld.aggr ? "write#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}String(\"#{ctx.fld.name}\", out, value.#{ctx.valGetter})" : "out.writeStringField(\"#{ctx.fld.name}\", value.#{ctx.valGetter})"
29
+ }
30
+ )
31
+
32
+ =begin rdoc
33
+ HDFS Reader and Writer for integral Java types such as Integer or Long.
34
+ =end
35
+ INTEGRAL_RW_METHODS = RwHolder.new(
36
+ lambda{ |ctx|
37
+ mapsNotSupported(ctx.fld) if ctx.fld.trgType # map
38
+ case
39
+ when ctx.fType.length <= 4; ctx.fld.aggr ? ctx.rw.call("read#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}Integer(in)") :
40
+ ctx.rw.call('in.getIntValue')
41
+
42
+ when ctx.fType.length <= 8; ; ctx.fld.aggr ? ctx.rw.call("read#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}Long(in)") : ctx.rw.call('in.getLongValue')
43
+
44
+ else; raise "Invalid integer field #{ctx.fld}"
45
+ end
46
+ },
47
+ lambda{ |ctx|
48
+ case
49
+ when ctx.fType.length <= 4; ctx.fld.aggr ? "write#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))
50
+ }Integer(\"#{ctx.fld.name}\", out, value.#{ctx.valGetter})" :
51
+ "out.writeNumberField(\"#{ctx.fld.name}\", value.#{ctx.valGetter})"
52
+
53
+ when ctx.fType.length <= 8; ctx.fld.aggr ? "write#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))
54
+ }Long(\"#{ctx.fld.name}\", out, value.#{ctx.valGetter})" :
55
+ "out.writeNumberField(\"#{ctx.fld.name}\", value.#{ctx.valGetter})"
56
+
57
+ else; raise "Invalid integer field #{ctx.fld}"
58
+ end
59
+ })
60
+
61
+ =begin rdoc
62
+ HDFS Reader and Writer for floating point Java types such as Float or Double.
63
+ =end
64
+ FLOAT_RW_METHODS = RwHolder.new(
65
+ lambda{|ctx|
66
+ mapsNotSupported(ctx.fld) if ctx.fld.trgType # map
67
+ case
68
+ when ctx.fType.length <= 4; ctx.fld.aggr ? ctx.rw.call("read#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}Float(in)") : ctx.rw.call('in.getFloatValue()')
69
+ when ctx.fType.length <= 8; ctx.fld.aggr ? ctx.rw.call("read#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}Double(in)") : ctx.rw.call('in.getDoubleValue()')
70
+ else; raise "Invalid float field #{ctx.fld}"
71
+ end
72
+ },
73
+ lambda{|ctx|
74
+ case
75
+ when ctx.fType.length <= 4; ctx.fld.aggr ? "write#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}Float(out, value.#{ctx.valGetter})" : "out.writeNumberField(\"#{ctx.fld.name}\", value.#{ctx.valGetter})"
76
+ when ctx.fType.length <= 8; ctx.fld.aggr ? "write#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}Double(out, value.#{ctx.valGetter})" : "out.writeNumberField(\"#{ctx.fld.name}\", value.#{ctx.valGetter})"
77
+ else; raise "Invalid float field #{ctx.fld}"
78
+ end
79
+ })
80
+
81
+ =begin rdoc
82
+ HDFS Reader and Writer for the temporal type, the DateTime
83
+ =end
84
+ DTTM_RW_METHODS = RwHolder.new(
85
+ lambda { |ctx|
86
+ ctx.fld.aggr ? ctx.rw.call("read#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}ZonedDateTime(in)") : ctx.rw.call('readDttm(in)')
87
+ },
88
+ lambda { |ctx|
89
+ ctx.fld.aggr ? %<write#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}ZonedDateTime("#{
90
+ ctx.fld.name}", out, value.#{ctx.valGetter})> : "writeDttmFld(\"#{ctx.fld.name}\", out, value.#{ctx.valGetter})"
91
+ }
92
+ )
93
+
94
+ =begin rdoc
95
+ HDFS Reader and Writer for boolean Java type.
96
+ =end
97
+ BOOL_RW_METHODS = RwHolder.new(
98
+ lambda { |ctx|
99
+ aggrNotSupported(ctx.fld, 'Booleans') if ctx.fld.aggr
100
+ ctx.rw.call('in.getBooleanValue()')
101
+ },
102
+ lambda { |ctx|
103
+ aggrNotSupported(ctx.fld, 'Booleans') if ctx.fld.aggr
104
+ "out.writeBooleanField(\"#{ctx.fld.name}\", value.#{ctx.valGetter})"
105
+ }
106
+ )
107
+
108
+ =begin rdoc
109
+ HDFS Reader and Writer the raw data type, the byte array.
110
+ =end
111
+ RAW_RW_METHODS = RwHolder.new(
112
+ lambda { |ctx|
113
+ aggrNotSupported(ctx.fld, 'Raw Data') if ctx.fld.aggr
114
+ ctx.rw.call('readByteArray(in)')
115
+ },
116
+ lambda { |ctx|
117
+ aggrNotSupported(ctx.fld, 'Raw Data') if ctx.fld.aggr
118
+ "writeByteArrayFld(\"#{ctx.fld.name}\", out, value.#{ctx.valGetter})" }
119
+ )
120
+
121
+ =begin rdoc
122
+ HDFS Reader and Writer the variable size Decimal data type.
123
+ =end
124
+ NUMERIC_RW_METHODS = RwHolder.new(lambda{|ctx| ctx.fld.aggr ? ctx.rw.call("read#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}BigDecimal(in)") : ctx.rw.call('readBigDecimal(in)')},
125
+ lambda{|ctx| "out.writeNumberField(\"#{ctx.fld.name}\", value.#{ctx.valGetter})"})
126
+
127
+ =begin rdoc
128
+ HDFS Reader and Writer the Java Enums.
129
+ =end
130
+ ENUM_RW_METHODS = RwHolder.new(
131
+ lambda{|ctx|
132
+ aggrNotSupported(ctx.fld, 'Enums') if ctx.fld.aggr
133
+ "#{DataMetaDom.condenseType(ctx.fType.type, ctx.pckg)}.forName(readText(in))"
134
+ },
135
+ lambda { |ctx|
136
+ aggrNotSupported(ctx.fld, 'Enums') if ctx.fld.aggr
137
+ "out.writeStringField(\"#{ctx.fld.name}\", value.#{ctx.valGetter}.name())"
138
+ }
139
+ )
140
+
141
+ =begin rdoc
142
+ HDFS Reader and Writer the BitSet.
143
+ =end
144
+ BITSET_RW_METHODS = RwHolder.new(
145
+ lambda { |ctx|
146
+ aggrNotSupported(ctx.fld, 'BitSets') if ctx.fld.aggr
147
+ "new #{DataMetaDom.condenseType(ctx.fld.dataType, ctx.pckg)}(readLongArray(in))"
148
+ },
149
+ lambda { |ctx|
150
+ aggrNotSupported(ctx.fld, 'BitSets') if ctx.fld.aggr
151
+ "writeBitSetFld(\"#{ctx.fld.name}\", out, value.#{ctx.valGetter})"
152
+ }
153
+ )
154
+
155
+ =begin rdoc
156
+ HDFS Reader and Writer the URL.
157
+ =end
158
+ URL_RW_METHODS = RwHolder.new(
159
+ lambda { |ctx|
160
+ aggrNotSupported(ctx.fld, 'URLs') if ctx.fld.aggr
161
+ 'new java.net.URL(readText(in))'
162
+ },
163
+ lambda { |ctx|
164
+ aggrNotSupported(ctx.fld, 'URLs') if ctx.fld.aggr
165
+ "out.writeStringField(\"#{ctx.fld.name}\", value.#{ctx.valGetter}.toExternalForm)"
166
+ }
167
+ )
168
+ =begin rdoc
169
+ Read/write methods for the standard data types.
170
+ =end
171
+ STD_RW_METHODS = {
172
+ INT => INTEGRAL_RW_METHODS,
173
+ STRING => TEXT_RW_METHODS,
174
+ DATETIME => DTTM_RW_METHODS,
175
+ BOOL => BOOL_RW_METHODS,
176
+ CHAR => TEXT_RW_METHODS,
177
+ FLOAT => FLOAT_RW_METHODS,
178
+ RAW => RAW_RW_METHODS,
179
+ NUMERIC => NUMERIC_RW_METHODS,
180
+ URL => URL_RW_METHODS
181
+ }
182
+ # DataMeta DOM object renderer
183
+ RECORD_RW_METHODS = RwHolder.new(
184
+ lambda { |ctx|
185
+ if ctx.fld.aggr
186
+ if ctx.fld.trgType # map
187
+ mapsNotSupported(ctx.fld)
188
+ else # list, set or deque
189
+ "read#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}(in, #{
190
+ jsonableClassName(DataMetaDom.condenseType(ctx.fType.type, ctx.pckg))})"
191
+ end
192
+ else # scalar
193
+ "#{jsonableClassName(DataMetaDom.condenseType(ctx.fType.type, ctx.pckg))}.read(in)"
194
+ end
195
+ },
196
+ lambda { |ctx|
197
+ if ctx.fld.aggr && !ctx.fld.trgType
198
+ if ctx.fld.trgType # map
199
+ mapsNotSupported(ctx.fld)
200
+ else # list, set or deque
201
+ "writeCollectionFld(\"#{ctx.fld.name}\", out, value.#{ctx.valGetter}, #{jsonableClassName(DataMetaDom.condenseType(ctx.fType.type, ctx.pckg))})"
202
+ end
203
+ else # scalar
204
+ "#{jsonableClassName(DataMetaDom.condenseType(ctx.fType.type, ctx.pckg))}.writeField(\"#{ctx.fld.name}\", out, value.#{ctx.valGetter})"
205
+ end
206
+ }
207
+ )
208
+
209
+ # Transforms the given DataMeta DOM aggregate type to full pathed Java class name
210
+ def aggrJavaFull(aggr)
211
+ PojoLexer::AGGR_CLASSES[aggr] || (raise ArgumentError, "No Aggregate classes for type #{aggr}" )
212
+ end
213
+
214
+ # Transforms the given full Java name for the aggregate class into base name to interpolate into methods
215
+ def aggrBaseName(aggr)
216
+ /^(\w+\.)+(\w+)$/.match(aggr)[2]
217
+ end
218
+ =begin rdoc
219
+ Read/write methods for the DataMeta DOM Maps, accidentally all the same as for the standard data types.
220
+ =end
221
+ MAP_RW_METHODS = STD_RW_METHODS
222
+
223
+ # Build the Read/Write operation renderer for the given context:
224
+ def getRwRenderer(ctx)
225
+ dt = ctx.fld.dataType
226
+ ctx.refType = nil # reset to avoid misrendering primitives
227
+ rwRenderer = STD_RW_METHODS[dt.type]
228
+ return rwRenderer if rwRenderer
229
+ refKey = dt.type
230
+ ctx.refType = ctx.model.enums[refKey] || ctx.model.records[refKey]
231
+ case
232
+ when ctx.refType.kind_of?(DataMetaDom::Record)
233
+ RECORD_RW_METHODS
234
+ when ctx.refType.kind_of?(DataMetaDom::Enum)
235
+ ENUM_RW_METHODS
236
+ when ctx.refType.kind_of?(DataMetaDom::BitSet)
237
+ BITSET_RW_METHODS
238
+ when ctx.refType.kind_of?(DataMetaDom::Mapping)
239
+ MAP_RW_METHODS[ctx.fType.type] || (raise ArgumentError, "No renderer found for the key type #{
240
+ ctx.fType.type}, record #{ctx.rec}, field #{ctx.fld}")
241
+ else
242
+ raise "No renderer defined for field #{ctx.fld}"
243
+ end
244
+ end
245
+
246
+ # Temporary/scratch var -- avoiding collisions at all costs
247
+ def tmpVar(name); "#{'_'*3}#{name}#{'_'*3}" end
248
+
249
+ # generates writable via delegation
250
+ def genJacksonable(model, ioOut, record, javaPackage, baseName)
251
+ ctx = RendCtx.new.init(model, record, javaPackage, baseName)
252
+ fields = record.fields
253
+ ioName = jsonableClassName(baseName)
254
+ # scan for imports needed
255
+ hasOptional = fields.values.map{|f|
256
+ # !model.records[f.dataType.type] &&
257
+ !f.isRequired
258
+ }.reduce(:|) # true if there is at least one optional field which isn't a record
259
+ #fields.values.each { |f|
260
+ # ctx << DataMetaDom::PojoLexer::JAVA_IMPORTS[f.dataType.type]
261
+ #}
262
+
263
+ # field keys (names) in the order of reading/writing to the in/out record
264
+ keysInOrder = fields.each_key.map{|k| k.to_s}.sort.map{|k| k.to_sym}
265
+ reads = ''
266
+ writes = ''
267
+ indent = "#{' ' * 2}"
268
+ # sorting provides predictable read/write order
269
+ keysInOrder.each { |k|
270
+ f = fields[k]
271
+ ctx.fld = f
272
+ rwRenderer = getRwRenderer(ctx)
273
+ # unless ctx.refType.kind_of?(DataMetaDom::Record)
274
+ reads << %/
275
+ #{indent*5}case "#{f.name}" =>
276
+ #{indent*6}value.#{DataMetaDom.setterName(ctx.fld)}(#{rwRenderer.r.call(ctx)})
277
+ /
278
+ # rendering of noReqFld - using the Veryfiable interface instead
279
+ #=begin
280
+ writes << ( "\n" + (indent*2) + (f.isRequired ?
281
+ (PRIMITIVABLE_TYPES.member?(f.dataType.type) ? '' : ''):
282
+ #%Q<if(value.#{DataMetaDom::PojoLexer::getterName(ctx.fld)}() == null) throw noReqFld("#{f.name}"); >) :
283
+ "if(value.#{DataMetaDom.getterName(ctx.fld)} != null) ") + "#{rwRenderer.w.call(ctx)}")
284
+ #=end
285
+ # end
286
+ }
287
+ ioOut.puts <<JSONABLE_CLASS
288
+ package #{javaPackage}
289
+
290
+ import org.ebay.datameta.ser.jackson.fasterxml.JacksonUtil._
291
+ import org.ebay.datameta.ser.jackson.fasterxml.Jsonable
292
+ import com.fasterxml.jackson.core.{JsonFactory, JsonGenerator, JsonParser, JsonToken}
293
+ import com.fasterxml.jackson.core.JsonToken.{END_ARRAY, END_OBJECT}
294
+
295
+ #{DataMetaDom::PojoLexer.classJavaDoc({})}object #{ioName} extends Jsonable[#{baseName}] {
296
+
297
+ override def write(out: JsonGenerator, value: #{baseName}) {
298
+ value.verify()
299
+ #{writes}
300
+ }
301
+
302
+ override def read(in: JsonParser, value: #{baseName}): #{baseName} = {
303
+ while(in.nextToken() != END_OBJECT) {
304
+ val fldName = in.getCurrentName
305
+ if(fldName != null) {
306
+ in.nextToken()
307
+ fldName match {
308
+ #{reads}
309
+ case _ => throw new IllegalArgumentException(s"""Unhandled field "$fldName" """)
310
+ }
311
+ }
312
+ }
313
+ value
314
+ }
315
+
316
+ override def read(in: JsonParser): #{baseName} = {
317
+ read(in, new #{baseName}())
318
+ }
319
+ }
320
+ JSONABLE_CLASS
321
+
322
+ end
323
+
324
+ =begin rdoc
325
+ Generates all the writables for the given model.
326
+ Parameters:
327
+ * +model+ - the model to generate Writables from.
328
+ * +outRoot+ - destination directory name.
329
+ =end
330
+ def genJacksonables(model, outRoot)
331
+ model.records.values.each { |e|
332
+ javaPackage, base, packagePath = DataMetaDom::PojoLexer::assertNamespace(e.name)
333
+ destDir = File.join(outRoot, packagePath)
334
+ FileUtils.mkdir_p destDir
335
+ ioOut = File.open(File.join(destDir, "#{jsonableClassName(base)}.scala"), 'wb')
336
+ begin
337
+ case
338
+ when e.kind_of?(DataMetaDom::Record)
339
+ genJacksonable model, ioOut, e, javaPackage, base
340
+ else
341
+ raise "Unsupported Entity: #{e.inspect}"
342
+ end
343
+ ensure
344
+ ioOut.close
345
+ end
346
+ }
347
+ end
348
+
349
+ # Shortcut to help for the Hadoop Writables generator.
350
+ def helpDataMetaJacksonSerGen(file, errorText=nil)
351
+ DataMetaDom::help(file, 'DataMeta Serialization to/from Jackson', '<DataMeta DOM source> <Target Directory>', errorText)
352
+ end
353
+
354
+ module_function :helpDataMetaJacksonSerGen, :genJacksonables, :genJacksonable, :getRwRenderer,
355
+ :aggrBaseName, :aggrJavaFull
356
+ end
@@ -0,0 +1,17 @@
1
+ # keep this underscore naming in the test subdir, it's easier to append files names to test
2
+ require './test/test_helper.rb'
3
+
4
+ # Unit test cases for the DataMetaByteSer
5
+ # See for instance:
6
+ # - test_full
7
+ class TestNewGem < Test::Unit::TestCase
8
+
9
+ # an empty stub for now
10
+ def setup;
11
+ end
12
+
13
+ # stub
14
+ def test_true
15
+ assert_equal('a', "a")
16
+ end
17
+ end
@@ -0,0 +1,4 @@
1
+ ## keep this underscore naming in the test subdir, it's easier to append files names to test
2
+ %w(stringio test/unit).each { |r| require r }
3
+ # this is expected to run from the project root, normally by the rake file
4
+ require './lib/dataMetaJacksonSer'
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dataMetaJacksonSer
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Michael Bergens
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-03-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dataMetaDom
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.0.4
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '1.0'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.0.4
33
+ description: Generates serializers of DataMeta objects to/from JSON using Fast XML
34
+ Jackson
35
+ email: michael.bergens@gmail.com
36
+ executables:
37
+ - dataMetaJacksonSerGen.rb
38
+ extensions: []
39
+ extra_rdoc_files: []
40
+ files:
41
+ - ".yardopts"
42
+ - History.md
43
+ - PostInstall.txt
44
+ - README.md
45
+ - Rakefile
46
+ - bin/dataMetaJacksonSerGen.rb
47
+ - lib/dataMetaJacksonSer.rb
48
+ - lib/dataMetaJacksonSer/util.rb
49
+ - test/test_dataMetaJacksonSer.rb
50
+ - test/test_helper.rb
51
+ homepage: https://github.com/eBayDataMeta
52
+ licenses:
53
+ - Apache-2.0
54
+ metadata: {}
55
+ post_install_message:
56
+ rdoc_options: []
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 2.1.1
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ requirements:
70
+ - Hadoop libraries
71
+ rubyforge_project:
72
+ rubygems_version: 2.5.1
73
+ signing_key:
74
+ specification_version: 4
75
+ summary: DataMeta JSON Serializers Gen using Fast XML Jackson
76
+ test_files:
77
+ - test/test_dataMetaJacksonSer.rb