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 +7 -0
- data/.yardopts +1 -0
- data/History.md +5 -0
- data/PostInstall.txt +1 -0
- data/README.md +35 -0
- data/Rakefile +13 -0
- data/bin/dataMetaJacksonSerGen.rb +17 -0
- data/lib/dataMetaJacksonSer/util.rb +133 -0
- data/lib/dataMetaJacksonSer.rb +356 -0
- data/test/test_dataMetaJacksonSer.rb +17 -0
- data/test/test_helper.rb +4 -0
- metadata +77 -0
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
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
|
data/test/test_helper.rb
ADDED
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
|