dataMetaJacksonSer 1.0.0 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: aaf9ff84148a45b237fedbc3145b843bc1877a38
4
- data.tar.gz: b902109105871f7aafc26ac1a29ea6aa48bd3ff8
3
+ metadata.gz: c280f23ebe6a3da38712640ba619481e38b333cf
4
+ data.tar.gz: 3739073a2393df9fe1592b25a5669afb4357c274
5
5
  SHA512:
6
- metadata.gz: fd5412944ff51009a98f019ae3755d9aa8d1d54d2170d66f1ad608d3fabbb6b66c42095a19f271e6ebd3b95eccae72051c5e57a2c6b52b42a96e8b4cf5192141
7
- data.tar.gz: 75708f115d9fb0d0b11c37a6151ccd92f85a74bc8b2630ff5b1fea36723298672b0e63af823eec74daad716bdba7f214ca094af1e63baec6aab03d00923c87b1
6
+ metadata.gz: f03544c1c869c9e20d3cc1abbfa15ff0f4471b9883944ab59bd63585c219be63e5ff71f9d16760e90a59c5043bdceda35541909a892fb6c33e46f70f164300d9
7
+ data.tar.gz: ca82e225b9d5cd143945da3b6b89d90e40cd99db4e780946577be02d774d80ad1ac7c78c3785941a15e4614bde81e50fa1d50c23fa08f06bc454070dfab70e6a
data/History.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # `dataMetaJacksonSer` Release history:
2
2
 
3
+ ## `2.0.2` released `2018-05-13 Sun` by [`mub`](https://github.com/mub)
4
+ * 1 update:
5
+ * Support for Enum serialization
6
+
7
+ ## `2.0.1` released `2017-04-18 Tue` by [`mub`](https://github.com/mub)
8
+ * 1 update:
9
+ * Added Java output format for Jsonables.
10
+
11
+ ## `2.0.0` released `2017-04-18 Tue` by [`mub`](https://github.com/mub)
12
+ * 1 major change:
13
+ * Added the `ignoreUnknown` parameter to the [`Jsonable[T]` trait](https://github.com/eBayDataMeta/DataMeta-domScala/blob/master/ser/jackson/fasterxml/src/main/scala/org/ebay/datameta/ser/jackson/fasterxml/Jsonable.scala), changed the generator to match
14
+
3
15
  ## `1.0.0` released `2017-04-04 Tue` by [`mub`](https://github.com/mub)
4
16
  * 1 major enhancement:
5
17
  * Initial release
data/README.md CHANGED
@@ -18,7 +18,7 @@ Generates (de)serializers to/from JSON using FasterXML Jackson.
18
18
 
19
19
  ## SYNOPSIS:
20
20
 
21
- To generate Byte Array serializers in Java, including Hadoop Writables for the DataMeta model, run:
21
+ To generate the JSON (de)serializers in Java, including Hadoop Writables for the DataMeta model, run:
22
22
 
23
23
  dataMetaJacksonSerGen.rb <DataMeta DOM source> <Target Directory>
24
24
 
@@ -1,17 +1,36 @@
1
1
  #!/usr/bin/env ruby
2
- %w( dataMetaDom dataMetaJacksonSer ).each(&method(:require))
2
+ %w( dataMetaDom dataMetaJacksonSer dataMetaJacksonSer/util ).each(&method(:require))
3
3
 
4
- @source, @target = ARGV
4
+ @source, @target, @formatSpec = ARGV
5
5
  DataMetaJacksonSer::helpDataMetaJacksonSerGen __FILE__ unless @source && @target
6
6
  DataMetaJacksonSer::helpDataMetaJacksonSerGen(__FILE__, "DataMeta DOM source #{@source} is not a file") unless File.file?(@source)
7
7
  DataMetaJacksonSer::helpDataMetaJacksonSerGen(__FILE__, "Jacksonables destination directory #{@target} is not a dir") unless File.directory?(@target)
8
8
 
9
+ @format = if @formatSpec.nil?
10
+ DataMetaJacksonSer::JAVA_FMT # default to Java
11
+ else
12
+ fmt = @formatSpec.to_sym
13
+ case fmt
14
+ # this should be verified (asserted) by the API methods too, but they would raise an error
15
+ # instead of showing help.
16
+ when DataMetaJacksonSer::JAVA_FMT, DataMetaJacksonSer::SCALA_FMT
17
+ fmt
18
+ else
19
+ DataMetaJacksonSer::helpDataMetaJacksonSerGen(__FILE__,
20
+ %/Unsupported output format "#{@formatSpec}", use "java" or "scala"/)
21
+ end
22
+ end
23
+
24
+ puts "Output format: #{@format}"
25
+
9
26
  @parser = DataMetaDom::Model.new
10
27
  begin
11
28
  @parser.parse(@source, options={autoVerNs: true})
12
- DataMetaJacksonSer::genJacksonables(@parser, @target)
29
+ DataMetaJacksonSer::genJacksonables(@parser, @target, @format)
13
30
  puts "Jackson serialization classes written to #{@target}. Done."
14
31
  rescue Exception => e
15
- $stderr.puts "ERROR #{e.message}; #{@parser.diagn}"
16
- $stderr.puts e.backtrace.inspect
32
+ indent = ' ' * 4
33
+ $stderr.puts %/ERROR #{e.message}; #{@parser.diagn}
34
+ #{indent}#{e.backtrace.join("\n#{indent}")}
35
+ /
17
36
  end
@@ -1,98 +1,98 @@
1
1
  $:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
2
2
 
3
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))
4
+ %w(fileutils dataMetaDom dataMetaDom/pojo dataMetaDom/enum dataMetaDom/record dataMetaDom/help dataMetaDom/util
5
+ ).each(&method(:require))
6
+
5
7
  require 'set'
6
8
  require 'dataMetaJacksonSer/util'
7
9
 
8
10
  =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].
11
+ JSON Serialization artifacts generation.
12
12
 
13
13
  For command line details either check the new method's source or the README.rdoc file, the usage section.
14
14
  =end
15
15
  module DataMetaJacksonSer
16
16
  # Current version
17
- VERSION = '1.0.0'
17
+ VERSION = '2.0.2'
18
18
  include DataMetaDom, DataMetaDom::PojoLexer
19
19
 
20
20
  =begin rdoc
21
- HDFS Reader and Writer for textual Java types such as String.
21
+ JSON Reader and Writer for textual Java types such as String.
22
22
  =end
23
23
  TEXT_RW_METHODS = RwHolder.new(
24
24
  lambda{|ctx|
25
- ctx.fld.aggr ? ctx.rw.call("read#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}String(in)") : ctx.rw.call('readText(in)')
25
+ ctx.fld.aggr ? ctx.rw.call("JU.read#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}String(in)") : ctx.rw.call('JU.readText(in)')
26
26
  },
27
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})"
28
+ ctx.fld.aggr ? ctx.rw.call("JU.write#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}String(\"#{ctx.fld.name}\", out, value.#{ctx.valGetter}#{ctx.|})") : "out.writeStringField(\"#{ctx.fld.name}\", value.#{ctx.valGetter}#{ctx.|})"
29
29
  }
30
30
  )
31
31
 
32
32
  =begin rdoc
33
- HDFS Reader and Writer for integral Java types such as Integer or Long.
33
+ JSON Reader and Writer for integral Java types such as Integer or Long.
34
34
  =end
35
35
  INTEGRAL_RW_METHODS = RwHolder.new(
36
36
  lambda{ |ctx|
37
37
  mapsNotSupported(ctx.fld) if ctx.fld.trgType # map
38
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')
39
+ when ctx.fType.length <= 4; ctx.fld.aggr ? ctx.rw.call("JU.read#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}Integer(in)") :
40
+ ctx.rw.call("in.getIntValue#{ctx.|}")
41
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')
42
+ when ctx.fType.length <= 8; ; ctx.fld.aggr ? ctx.rw.call("JU.read#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}Long(in)") : ctx.rw.call("in.getLongValue#{ctx.|}")
43
43
 
44
44
  else; raise "Invalid integer field #{ctx.fld}"
45
45
  end
46
46
  },
47
47
  lambda{ |ctx|
48
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})"
49
+ when ctx.fType.length <= 4; ctx.fld.aggr ? "JU.write#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))
50
+ }Integer(\"#{ctx.fld.name}\", out, value.#{ctx.valGetter}#{ctx.|})" :
51
+ "out.writeNumberField(\"#{ctx.fld.name}\", value.#{ctx.valGetter}#{ctx.|})"
52
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})"
53
+ when ctx.fType.length <= 8; ctx.fld.aggr ? "JU.write#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))
54
+ }Long(\"#{ctx.fld.name}\", out, value.#{ctx.valGetter}#{ctx.|})" :
55
+ "out.writeNumberField(\"#{ctx.fld.name}\", value.#{ctx.valGetter}#{ctx.|})"
56
56
 
57
57
  else; raise "Invalid integer field #{ctx.fld}"
58
58
  end
59
59
  })
60
60
 
61
61
  =begin rdoc
62
- HDFS Reader and Writer for floating point Java types such as Float or Double.
62
+ JSON Reader and Writer for floating point Java types such as Float or Double.
63
63
  =end
64
64
  FLOAT_RW_METHODS = RwHolder.new(
65
65
  lambda{|ctx|
66
66
  mapsNotSupported(ctx.fld) if ctx.fld.trgType # map
67
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()')
68
+ when ctx.fType.length <= 4; ctx.fld.aggr ? ctx.rw.call("JU.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("JU.read#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}Double(in)") : ctx.rw.call('in.getDoubleValue()')
70
70
  else; raise "Invalid float field #{ctx.fld}"
71
71
  end
72
72
  },
73
73
  lambda{|ctx|
74
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})"
75
+ when ctx.fType.length <= 4; ctx.fld.aggr ? "JU.write#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}Float(\"#{ctx.fld.name}\", out, value.#{ctx.valGetter}#{ctx.|})" : "out.writeNumberField(\"#{ctx.fld.name}\", value.#{ctx.valGetter}#{ctx.|})"
76
+ when ctx.fType.length <= 8; ctx.fld.aggr ? "JU.write#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}Double(\"#{ctx.fld.name}\", out, value.#{ctx.valGetter}#{ctx.|})" : "out.writeNumberField(\"#{ctx.fld.name}\", value.#{ctx.valGetter}#{ctx.|})"
77
77
  else; raise "Invalid float field #{ctx.fld}"
78
78
  end
79
79
  })
80
80
 
81
81
  =begin rdoc
82
- HDFS Reader and Writer for the temporal type, the DateTime
82
+ JSON Reader and Writer for the temporal type, the DateTime
83
83
  =end
84
84
  DTTM_RW_METHODS = RwHolder.new(
85
85
  lambda { |ctx|
86
- ctx.fld.aggr ? ctx.rw.call("read#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}ZonedDateTime(in)") : ctx.rw.call('readDttm(in)')
86
+ ctx.fld.aggr ? ctx.rw.call("JU.read#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}ZonedDateTime(in)") : ctx.rw.call('JU.readDttm(in)')
87
87
  },
88
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})"
89
+ ctx.fld.aggr ? %<JU.write#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}ZonedDateTime("#{
90
+ ctx.fld.name}", out, value.#{ctx.valGetter}#{ctx.|})> : "JU.writeDttmFld(\"#{ctx.fld.name}\", out, value.#{ctx.valGetter}#{ctx.|})"
91
91
  }
92
92
  )
93
93
 
94
94
  =begin rdoc
95
- HDFS Reader and Writer for boolean Java type.
95
+ JSON Reader and Writer for boolean Java type.
96
96
  =end
97
97
  BOOL_RW_METHODS = RwHolder.new(
98
98
  lambda { |ctx|
@@ -101,45 +101,43 @@ HDFS Reader and Writer for boolean Java type.
101
101
  },
102
102
  lambda { |ctx|
103
103
  aggrNotSupported(ctx.fld, 'Booleans') if ctx.fld.aggr
104
- "out.writeBooleanField(\"#{ctx.fld.name}\", value.#{ctx.valGetter})"
104
+ "out.writeBooleanField(\"#{ctx.fld.name}\", value.#{ctx.valGetter}#{ctx.|})"
105
105
  }
106
106
  )
107
107
 
108
108
  =begin rdoc
109
- HDFS Reader and Writer the raw data type, the byte array.
109
+ JSON Reader and Writer the raw data type, the byte array.
110
110
  =end
111
111
  RAW_RW_METHODS = RwHolder.new(
112
112
  lambda { |ctx|
113
113
  aggrNotSupported(ctx.fld, 'Raw Data') if ctx.fld.aggr
114
- ctx.rw.call('readByteArray(in)')
114
+ ctx.rw.call('JU.readByteArrayPrim(in)')
115
115
  },
116
116
  lambda { |ctx|
117
117
  aggrNotSupported(ctx.fld, 'Raw Data') if ctx.fld.aggr
118
- "writeByteArrayFld(\"#{ctx.fld.name}\", out, value.#{ctx.valGetter})" }
118
+ "JU.writeByteArrayFld(\"#{ctx.fld.name}\", out, value.#{ctx.valGetter}#{ctx.|})" }
119
119
  )
120
120
 
121
121
  =begin rdoc
122
- HDFS Reader and Writer the variable size Decimal data type.
122
+ JSON Reader and Writer the variable size Decimal data type.
123
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})"})
124
+ NUMERIC_RW_METHODS = RwHolder.new(lambda{|ctx| ctx.fld.aggr ? ctx.rw.call("JU.read#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}BigDecimal(in)") : ctx.rw.call('JU.readBigDecimal(in)')},
125
+ lambda{|ctx| "out.writeNumberField(\"#{ctx.fld.name}\", value.#{ctx.valGetter}#{ctx.|})"})
126
126
 
127
127
  =begin rdoc
128
- HDFS Reader and Writer the Java Enums.
128
+ JSON Reader and Writer the Java Enums.
129
129
  =end
130
130
  ENUM_RW_METHODS = RwHolder.new(
131
131
  lambda{|ctx|
132
- aggrNotSupported(ctx.fld, 'Enums') if ctx.fld.aggr
133
- "#{DataMetaDom.condenseType(ctx.fType.type, ctx.pckg)}.forName(readText(in))"
132
+ ctx.fld.aggr ? "JU.read#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}Enum(in, #{ctx.fType.type}.class)" : "Enum.valueOf(#{DataMetaDom.condenseType(ctx.fType.type, ctx.pckg)}.class, JU.readText(in))"
134
133
  },
135
134
  lambda { |ctx|
136
- aggrNotSupported(ctx.fld, 'Enums') if ctx.fld.aggr
137
- "out.writeStringField(\"#{ctx.fld.name}\", value.#{ctx.valGetter}.name())"
135
+ ctx.fld.aggr ? %<JU.write#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}Enum("#{ctx.fld.name}", out, value.#{ctx.valGetter}#{ctx.|})> : "out.writeStringField(\"#{ctx.fld.name}\", value.#{ctx.valGetter}#{ctx.|}.name())"
138
136
  }
139
137
  )
140
138
 
141
139
  =begin rdoc
142
- HDFS Reader and Writer the BitSet.
140
+ JSON Reader and Writer the BitSet.
143
141
  =end
144
142
  BITSET_RW_METHODS = RwHolder.new(
145
143
  lambda { |ctx|
@@ -148,21 +146,21 @@ HDFS Reader and Writer the BitSet.
148
146
  },
149
147
  lambda { |ctx|
150
148
  aggrNotSupported(ctx.fld, 'BitSets') if ctx.fld.aggr
151
- "writeBitSetFld(\"#{ctx.fld.name}\", out, value.#{ctx.valGetter})"
149
+ "writeBitSetFld(\"#{ctx.fld.name}\", out, value.#{ctx.valGetter}#{ctx.|})"
152
150
  }
153
151
  )
154
152
 
155
153
  =begin rdoc
156
- HDFS Reader and Writer the URL.
154
+ JSON Reader and Writer the URL.
157
155
  =end
158
156
  URL_RW_METHODS = RwHolder.new(
159
157
  lambda { |ctx|
160
158
  aggrNotSupported(ctx.fld, 'URLs') if ctx.fld.aggr
161
- 'new java.net.URL(readText(in))'
159
+ 'new java.net.URL(in.getText())'
162
160
  },
163
161
  lambda { |ctx|
164
162
  aggrNotSupported(ctx.fld, 'URLs') if ctx.fld.aggr
165
- "out.writeStringField(\"#{ctx.fld.name}\", value.#{ctx.valGetter}.toExternalForm)"
163
+ "out.writeStringField(\"#{ctx.fld.name}\", value.#{ctx.valGetter}#{ctx.|}.toExternalForm())"
166
164
  }
167
165
  )
168
166
  =begin rdoc
@@ -186,11 +184,11 @@ Read/write methods for the standard data types.
186
184
  if ctx.fld.trgType # map
187
185
  mapsNotSupported(ctx.fld)
188
186
  else # list, set or deque
189
- "read#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}(in, #{
190
- jsonableClassName(DataMetaDom.condenseType(ctx.fType.type, ctx.pckg))})"
187
+ "JU.read#{aggrBaseName(aggrJavaFull(ctx.fld.aggr))}(in, #{
188
+ jsonableClassName(DataMetaDom.condenseType(ctx.fType.type, ctx.pckg))}.getInstance())"
191
189
  end
192
190
  else # scalar
193
- "#{jsonableClassName(DataMetaDom.condenseType(ctx.fType.type, ctx.pckg))}.read(in)"
191
+ "#{jsonableClassName(DataMetaDom.condenseType(ctx.fType.type, ctx.pckg))}.getInstance().read(in)"
194
192
  end
195
193
  },
196
194
  lambda { |ctx|
@@ -198,10 +196,10 @@ Read/write methods for the standard data types.
198
196
  if ctx.fld.trgType # map
199
197
  mapsNotSupported(ctx.fld)
200
198
  else # list, set or deque
201
- "writeCollectionFld(\"#{ctx.fld.name}\", out, value.#{ctx.valGetter}, #{jsonableClassName(DataMetaDom.condenseType(ctx.fType.type, ctx.pckg))})"
199
+ "JU.writeCollectionFld(\"#{ctx.fld.name}\", out, value.#{ctx.valGetter}#{ctx.|}, #{jsonableClassName(DataMetaDom.condenseType(ctx.fType.type, ctx.pckg))}.getInstance())"
202
200
  end
203
201
  else # scalar
204
- "#{jsonableClassName(DataMetaDom.condenseType(ctx.fType.type, ctx.pckg))}.writeField(\"#{ctx.fld.name}\", out, value.#{ctx.valGetter})"
202
+ "#{jsonableClassName(DataMetaDom.condenseType(ctx.fType.type, ctx.pckg))}.getInstance().writeField(\"#{ctx.fld.name}\", out, value.#{ctx.valGetter}#{ctx.|})"
205
203
  end
206
204
  }
207
205
  )
@@ -246,8 +244,9 @@ Read/write methods for the DataMeta DOM Maps, accidentally all the same as for t
246
244
  # Temporary/scratch var -- avoiding collisions at all costs
247
245
  def tmpVar(name); "#{'_'*3}#{name}#{'_'*3}" end
248
246
 
249
- # generates writable via delegation
250
- def genJacksonable(model, ioOut, record, javaPackage, baseName)
247
+ # generates Scala JSONable via delegation
248
+ def genJacksonable(model, ioOut, record, javaPackage, baseName, fmt = :scala)
249
+ assertOutFmt fmt
251
250
  ctx = RendCtx.new.init(model, record, javaPackage, baseName)
252
251
  fields = record.fields
253
252
  ioName = jsonableClassName(baseName)
@@ -271,20 +270,44 @@ Read/write methods for the DataMeta DOM Maps, accidentally all the same as for t
271
270
  ctx.fld = f
272
271
  rwRenderer = getRwRenderer(ctx)
273
272
  # 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)})
273
+
274
+ reads << case fmt
275
+ when SCALA_FMT
276
+ %/
277
+ #{indent*5}case "#{f.name}" =>
278
+ #{indent*6}target.#{DataMetaDom.setterName(ctx.fld)}(#{rwRenderer.r.call(ctx)})
277
279
  /
278
- # rendering of noReqFld - using the Veryfiable interface instead
280
+ when JAVA_FMT
281
+ %/
282
+ #{indent*6}case "#{f.name}":
283
+ #{indent*7}target.#{DataMetaDom.setterName(ctx.fld)}(#{rwRenderer.r.call(ctx)});
284
+ #{indent*7}break;
285
+ /
286
+ else
287
+ badFmt fmt
288
+ end
289
+
290
+ # rendering of noReqFld - using the Verifiable interface instead
279
291
  #=begin
280
- writes << ( "\n" + (indent*2) + (f.isRequired ?
292
+ writes << case fmt
293
+ when SCALA_FMT
294
+ "\n" + (indent*2) + (f.isRequired ?
281
295
  (PRIMITIVABLE_TYPES.member?(f.dataType.type) ? '' : ''):
282
296
  #%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)}")
297
+ "if(value.#{DataMetaDom.getterName(ctx.fld)} != null) ") + "#{rwRenderer.w.call(ctx)}"
284
298
  #=end
285
- # end
299
+ when JAVA_FMT
300
+ "\n" + (indent*2) + (f.isRequired ?
301
+ (PRIMITIVABLE_TYPES.member?(f.dataType.type) ? '' : ''):
302
+ "if(value.#{DataMetaDom.getterName(ctx.fld)}#{ctx.|} != null) ") + "#{rwRenderer.w.call(ctx)};"
303
+ else
304
+ badFmt fmt
305
+ end
286
306
  }
287
- ioOut.puts <<JSONABLE_CLASS
307
+
308
+ ioOut.puts case fmt
309
+ when SCALA_FMT
310
+ %^
288
311
  package #{javaPackage}
289
312
 
290
313
  import org.ebay.datameta.ser.jackson.fasterxml.JacksonUtil._
@@ -299,25 +322,95 @@ import com.fasterxml.jackson.core.JsonToken.{END_ARRAY, END_OBJECT}
299
322
  #{writes}
300
323
  }
301
324
 
302
- override def read(in: JsonParser, value: #{baseName}): #{baseName} = {
325
+ override def readInto(in: JsonParser, target: #{baseName}, ignoreUnknown: Boolean = true): #{baseName} = {
303
326
  while(in.nextToken() != END_OBJECT) {
304
327
  val fldName = in.getCurrentName
305
328
  if(fldName != null) {
306
329
  in.nextToken()
307
330
  fldName match {
308
331
  #{reads}
309
- case _ => throw new IllegalArgumentException(s"""Unhandled field "$fldName" """)
332
+ case _ => if(!ignoreUnknown) throw new IllegalArgumentException(s"""Unhandled field "$fldName" """)
333
+ }
334
+ }
335
+ }
336
+ target
337
+ }
338
+
339
+ override def read(in: JsonParser, ignoreUnknown: Boolean = true): #{baseName} = {
340
+ readInto(in, new #{baseName}(), ignoreUnknown)
341
+ }
342
+ }
343
+ ^
344
+ when JAVA_FMT
345
+ %^
346
+ package #{javaPackage};
347
+
348
+ import static org.ebay.datameta.ser.jackson.fasterxml.JacksonUtil.*;
349
+ import org.ebay.datameta.ser.jackson.fasterxml.JacksonUtil;
350
+ import org.ebay.datameta.ser.jackson.fasterxml.Jsonable;
351
+ import com.fasterxml.jackson.core.JsonFactory;
352
+ import com.fasterxml.jackson.core.JsonGenerator;
353
+ import com.fasterxml.jackson.core.JsonParser;
354
+ import com.fasterxml.jackson.core.JsonToken;
355
+
356
+ import java.io.IOException;
357
+
358
+ import static com.fasterxml.jackson.core.JsonToken.END_ARRAY;
359
+ import static com.fasterxml.jackson.core.JsonToken.END_OBJECT;
360
+
361
+ /**
362
+ * Json Serializer/Deserializer for the type {@link #{baseName}}.
363
+ * This class is completely immutable, state-free and therefore thread-safe, implemented and used as a singleton.
364
+ */
365
+ #{DataMetaDom::PojoLexer.classJavaDoc({})}public class #{ioName} extends Jsonable<#{baseName}> {
366
+
367
+ /** An instance of the {@link JacksonUtil} - can use it anywhere because {@link JacksonUtil} is a singleton,
368
+ * immutable and state-free.
369
+ */
370
+ public final static JacksonUtil JU = JacksonUtil.getInstance();
371
+
372
+ public static #{ioName} getInstance() { return INSTANCE; }
373
+
374
+ private final static #{ioName} INSTANCE = new #{ioName}();
375
+
376
+ /**
377
+ * Constructor is private - use {@link #getInstance()} to get an instance.
378
+ */
379
+ private #{ioName}() {}
380
+
381
+ public void write(final JsonGenerator out, final #{baseName} value) throws IOException {
382
+ value.verify();
383
+ #{writes}
384
+ }
385
+
386
+ public #{baseName} readInto(final JsonParser in, final #{baseName} target, final boolean ignoreUnknown) throws IOException {
387
+ JsonToken t = null;
388
+ while ( (t = in.nextToken()) != END_OBJECT) {
389
+ if(t == null) throw new IllegalArgumentException("NULL token at " + in.getParsingContext());
390
+ final String fldName = in.getCurrentName();
391
+ if(fldName != null) {
392
+ in.nextToken();
393
+ switch(fldName){
394
+ case "#{VER_KEY}": break; // skip the version field
395
+ case "#{DT_KEY}": break; // skip the data type field
396
+ #{reads}
397
+ default:
398
+ if(!ignoreUnknown) throw new IllegalArgumentException("Unhandled field \\"" + fldName + '\\"');
310
399
  }
311
400
  }
312
401
  }
313
- value
402
+ return target;
314
403
  }
315
404
 
316
- override def read(in: JsonParser): #{baseName} = {
317
- read(in, new #{baseName}())
405
+ public #{baseName} read(final JsonParser in, boolean ignoreUnknown) throws IOException {
406
+ return readInto(in, new #{baseName}(), ignoreUnknown);
318
407
  }
319
408
  }
320
- JSONABLE_CLASS
409
+ ^
410
+ else
411
+ badFmt fmt
412
+
413
+ end
321
414
 
322
415
  end
323
416
 
@@ -327,16 +420,17 @@ Parameters:
327
420
  * +model+ - the model to generate Writables from.
328
421
  * +outRoot+ - destination directory name.
329
422
  =end
330
- def genJacksonables(model, outRoot)
423
+ def genJacksonables(model, outRoot, fmt = :scala)
424
+ assertOutFmt fmt
331
425
  model.records.values.each { |e|
332
426
  javaPackage, base, packagePath = DataMetaDom::PojoLexer::assertNamespace(e.name)
333
427
  destDir = File.join(outRoot, packagePath)
334
428
  FileUtils.mkdir_p destDir
335
- ioOut = File.open(File.join(destDir, "#{jsonableClassName(base)}.scala"), 'wb')
429
+ ioOut = File.open(File.join(destDir, "#{jsonableClassName(base)}.#{fmt}"), 'wb')
336
430
  begin
337
431
  case
338
432
  when e.kind_of?(DataMetaDom::Record)
339
- genJacksonable model, ioOut, e, javaPackage, base
433
+ genJacksonable model, ioOut, e, javaPackage, base, fmt
340
434
  else
341
435
  raise "Unsupported Entity: #{e.inspect}"
342
436
  end
@@ -348,7 +442,7 @@ Parameters:
348
442
 
349
443
  # Shortcut to help for the Hadoop Writables generator.
350
444
  def helpDataMetaJacksonSerGen(file, errorText=nil)
351
- DataMetaDom::help(file, 'DataMeta Serialization to/from Jackson', '<DataMeta DOM source> <Target Directory>', errorText)
445
+ DataMetaDom::help(file, 'DataMeta Serialization to/from Jackson', '<DataMeta DOM source> <Target Directory> [java | scala]', errorText)
352
446
  end
353
447
 
354
448
  module_function :helpDataMetaJacksonSerGen, :genJacksonables, :genJacksonable, :getRwRenderer,
@@ -5,6 +5,28 @@ require 'logger'
5
5
 
6
6
  module DataMetaJacksonSer
7
7
 
8
+ =begin rdoc
9
+ Output format: Scala.
10
+ =end
11
+ SCALA_FMT = :scala
12
+
13
+ =begin rdoc
14
+ Output format: Java.
15
+ =end
16
+ JAVA_FMT = :java
17
+
18
+ =begin rdoc
19
+ The key for the Version field in the generated JSON.
20
+ The "=" symbol is used to avoid any collision with fields/variables.
21
+ =end
22
+ VER_KEY = '*v*'
23
+
24
+ =begin rdoc
25
+ The key for the DataType field in the generated JSON.
26
+ The "=" symbol is used to avoid any collision with fields/variables.
27
+ =end
28
+ DT_KEY = '*dt*'
29
+
8
30
  =begin rdoc
9
31
  A holder for a read renderer and a write renderer, those come in pairs that have to be consistent so the
10
32
  data is read and written uniformly.
@@ -55,6 +77,11 @@ Base name of the type, without a namespace.
55
77
  The data type of the entity on the context.
56
78
  =end
57
79
  attr_accessor :refType
80
+
81
+ =begin rdoc
82
+ Rendering format: either JAVA_FMT or SCALA_FMT
83
+ =end
84
+ attr_accessor :fmt
58
85
  =begin rdoc
59
86
  Field currently on the context.
60
87
  =end
@@ -63,7 +90,7 @@ Field currently on the context.
63
90
  =begin rdoc
64
91
  Creates a new context.
65
92
  =end
66
- def initialize; @imps = Set.new end
93
+ def initialize; @imps = Set.new; @fmt = JAVA_FMT end
67
94
 
68
95
  =begin rdoc
69
96
  Setter for the field on the context, the field currently worked on.
@@ -74,7 +101,37 @@ Setter for the field on the context, the field currently worked on.
74
101
  Initialize the context with the model, the record, the package and the basename.
75
102
  Returns self for call chaining.
76
103
  =end
77
- def init(model, rec, pckg, baseName); @model = model; @rec = rec; @pckg = pckg; @baseName = baseName; self end
104
+ def init(model, rec, pckg, baseName, fmt = JAVA_FMT)
105
+ @model = model; @rec = rec; @pckg = pckg; @baseName = baseName
106
+ @fmt = DataMetaJacksonSer::assertOutFmt(fmt)
107
+ self
108
+ end
109
+
110
+ =begin rdoc
111
+ End of line for the given format - for Java, it's a semicolon, for Scala - empty string
112
+ =end
113
+ def /
114
+ case fmt
115
+ when JAVA_FMT
116
+ ';'
117
+ when SCALA_FMT
118
+ ''
119
+ # all the other options are weeded out in init(...) by calling assertOutFmt
120
+ end
121
+ end
122
+
123
+ =begin rdoc
124
+ Method call Parentheses for the given format - for Java, it's (), for Scala - empty string
125
+ =end
126
+ def |
127
+ case fmt
128
+ when JAVA_FMT
129
+ '()'
130
+ when SCALA_FMT
131
+ ''
132
+ # all the other options are weeded out in init(...) by calling assertOutFmt
133
+ end
134
+ end
78
135
 
79
136
  =begin rdoc
80
137
  Add an import to the context, returns self for call chaining.
@@ -116,6 +173,21 @@ Getter name for the current field, if the type is Mapping, includes <tt>.getKey(
116
173
  end
117
174
  end # RendCtx
118
175
 
176
+ # Helper error raiser for an unsupported JSONable format
177
+ def badFmt(fmt)
178
+ raise ArgumentError, %<Unsupported JSONable format "#{fmt}, use "java" or "scala"">
179
+ end
180
+
181
+ # Verifies the validity of the output format, raises an error if it's wrong.
182
+ def assertOutFmt(fmt)
183
+ case fmt
184
+ when JAVA_FMT, SCALA_FMT
185
+ fmt
186
+ else
187
+ badFmt fmt
188
+ end
189
+ end
190
+
119
191
  =begin rdoc
120
192
  Builds a class name for a InOutable.
121
193
  =end
@@ -129,5 +201,5 @@ Builds a class name for a InOutable.
129
201
  raise ArgumentError, "Field #{fld.name}: aggregate types are not supported for #{forWhat} on JSON serialization layer"
130
202
  end
131
203
 
132
- module_function :jsonableClassName, :mapsNotSupported, :aggrNotSupported
204
+ module_function :jsonableClassName, :mapsNotSupported, :aggrNotSupported, :assertOutFmt, :badFmt
133
205
  end
@@ -0,0 +1,60 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
2
+
3
+ require 'dataMetaDom/field'
4
+ require 'dataMetaDom/pojo'
5
+
6
+
7
+ module DataMetaJacksonSer
8
+ =begin rdoc
9
+ Migration tooling.
10
+
11
+ =end
12
+ module VerReadsJson
13
+ include DataMetaDom, DataMetaDom::PojoLexer
14
+ =begin
15
+ Generates Versioned Read switch that channels the read to the proper migration scenario.
16
+ =end
17
+ def genVerReadSwitchJson(v1, v2, modelForVer, vers, outRoot)
18
+ # v1 = mo1.records.values.first.ver.full
19
+ # v2 = mo2.records.values.first.ver.full
20
+ mo1 = modelForVer.call(v1)
21
+ mo2 = modelForVer.call(v2)
22
+ destDir = outRoot
23
+ javaPackage = '' # set the scope for the var
24
+ vars = OpenStruct.new # for template's local variables. ERB does not make them visible to the binding
25
+ # sort the models by versions out, 2nd to be the latest:
26
+ raise ArgumentError, "Versions on the model are the same: #{v1}" if v1 == v2
27
+ if v1 > v2
28
+ model2 = mo1
29
+ model1 = mo2
30
+ ver1 = v2
31
+ ver2 = v1
32
+ else
33
+ model2 = mo2
34
+ model1 = mo1
35
+ ver1 = v1
36
+ ver2 = v2
37
+ end
38
+ puts "Going from ver #{ver1} to #{ver2}"
39
+ trgE = model2.records.values.first
40
+ javaPackage, baseName, packagePath = assertNamespace(trgE.name)
41
+ javaClassName = "Read__SwitchJson_v#{ver1.toVarName}_to_v#{ver2.toVarName}"
42
+ destDir = File.join(outRoot, packagePath)
43
+ FileUtils.mkdir_p destDir
44
+ javaDestFile = File.join(destDir, "#{javaClassName}.java")
45
+
46
+ skippedCount = 0
47
+ if File.file?(javaDestFile)
48
+ skippedCount += 1
49
+ $stderr.puts %<Read switch target "#{javaDestFile} present, therefore skipped">
50
+ else
51
+ IO::write(javaDestFile,
52
+ ERB.new(IO.read(File.join(File.dirname(__FILE__), '../../tmpl/readSwitch.erb')),
53
+ $SAFE, '%<>').result(binding), mode: 'wb')
54
+ end
55
+
56
+ $stderr.puts %<Read Switch targets skipped: #{skippedCount}> if skippedCount > 0
57
+ end
58
+ module_function :genVerReadSwitchJson
59
+ end
60
+ end
@@ -0,0 +1,67 @@
1
+ <%#
2
+ Template for Java migration guides
3
+ %>
4
+ package <%=javaPackage%>;
5
+ /*
6
+ This class is generated by DataMeta DOM. Do not edit manually!
7
+ */
8
+ import com.fasterxml.jackson.core.JsonFactory;
9
+ import org.ebay.datameta.ser.jackson.fasterxml.JacksonUtil;
10
+ import org.ebay.datameta.ser.jackson.fasterxml.VerAndDataType;
11
+ import org.ebay.datameta.util.jdk.SemanticVersion;
12
+
13
+ import java.io.IOException;
14
+
15
+ public class <%=javaClassName%> {
16
+
17
+ private static final <%=javaClassName%> INSTANCE = new <%=javaClassName%>();
18
+
19
+ public static <%=javaClassName%> getInstance() { return INSTANCE; }
20
+
21
+ public static final JsonFactory JF = JacksonUtil.getInstance().getJf();
22
+
23
+ <% model2.records.values.each { |trgE|
24
+ vars.versCases = vers.clone.select{|v| v < ver2}.sort{|x, y| y<=>x}
25
+ vars.javaPackage, vars.baseName, vars.packagePath = assertNamespace(trgE.name)
26
+ srcRecName = flipVer(trgE.name, ver2.toVarName, ver1.toVarName)
27
+ srcE = model1.records[srcRecName]
28
+ if srcE
29
+ %>
30
+ public <%= vars.baseName %> read_<%= vars.baseName %>_versioned(final String json) throws IOException {
31
+ final VerAndDataType vdt = VerAndDataType.fromJson(json);
32
+ final SemanticVersion ver = vdt.getVersion();
33
+ if(ver.equals(<%=vars.baseName%>.VERSION)) {
34
+ return <%=vars.baseName%>_JSONable.getInstance().read(JF.createParser(json));
35
+ <%
36
+ while vars.versCases.length > 0 # loop through the case statement - a version per each
37
+ vars.switchTargVer = vars.versCases.shift
38
+ vars.brackets = ''
39
+ caseObjName = flipVer(trgE.name, ver2.toVarName, vars.switchTargVer.toVarName)
40
+ caseMod = modelForVer.call(vars.switchTargVer)
41
+ next unless caseMod.records.keys.member?(caseObjName.to_sym) # skip cases for the versions where this object's target version does not exist
42
+ %>
43
+ }
44
+ else if(ver.equals(<%=caseObjName%>.VERSION)){<% vars.versMigr = vers.clone.select{|v| v <= ver2}.sort{|x, y| y<=>x}%>
45
+ return <% while vars.versMigr.length > 0 # migration steps loop nested in the case statement loop
46
+ vars.brackets << ')'
47
+ vars.migrTargVer = vars.versMigr.shift # target version for migration loop
48
+ vars.srcVer = vars.versMigr[0]
49
+ vars.srcType = flipVer(trgE.name, ver2.toVarName, vars.srcVer.toVarName)
50
+ migrMod = modelForVer.call(vars.srcVer)
51
+ break unless migrMod.records.keys.member?(vars.srcType.to_sym) # enough if there is no record in the target version
52
+ vars.jpMigr = vars.javaPackage.gsub(".v#{ver2.toVarName}", ".v#{vars.migrTargVer.toVarName}")
53
+ %>
54
+ // substituting in <%=vars.javaPackage%>: ".v<%=ver2.toVarName%>" with ".v<%=vars.migrTargVer.toVarName%>"
55
+ <%=vars.jpMigr%>.<%=migrClass(vars.baseName, vars.srcVer, vars.migrTargVer)%>.getInstance().migrate(<% break if vars.srcVer <= vars.switchTargVer
56
+ end # migration steps loop %>
57
+
58
+ <%=vars.srcType%>_JSONable.getInstance().read(JF.createParser(json))
59
+ <%= vars.brackets %>;
60
+ <% end %>
61
+ }
62
+ else throw new IllegalArgumentException("Unsupported version for the record <%=vars.baseName%>: " + ver);
63
+ }
64
+ <% end
65
+ } # records loop %>
66
+ }
67
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dataMetaJacksonSer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Bergens
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-31 00:00:00.000000000 Z
11
+ date: 2018-05-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dataMetaDom
@@ -46,8 +46,10 @@ files:
46
46
  - bin/dataMetaJacksonSerGen.rb
47
47
  - lib/dataMetaJacksonSer.rb
48
48
  - lib/dataMetaJacksonSer/util.rb
49
+ - lib/dataMetaJacksonSer/ver_reads.rb
49
50
  - test/test_dataMetaJacksonSer.rb
50
51
  - test/test_helper.rb
52
+ - tmpl/readSwitch.erb
51
53
  homepage: https://github.com/eBayDataMeta
52
54
  licenses:
53
55
  - Apache-2.0
@@ -69,9 +71,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
69
71
  requirements:
70
72
  - Hadoop libraries
71
73
  rubyforge_project:
72
- rubygems_version: 2.5.1
74
+ rubygems_version: 2.5.2.1
73
75
  signing_key:
74
76
  specification_version: 4
75
- summary: DataMeta JSON Serializers Gen using Fast XML Jackson
77
+ summary: DataMeta JSON Serializers Gem using Fast XML Jackson
76
78
  test_files:
77
79
  - test/test_dataMetaJacksonSer.rb