jaxb2ruby 0.0.1-java
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/bin/jaxb2ruby +90 -0
- data/lib/jaxb2ruby.rb +15 -0
- data/lib/jaxb2ruby/classes.rb +184 -0
- data/lib/jaxb2ruby/config.xjb +16 -0
- data/lib/jaxb2ruby/converter.rb +250 -0
- data/lib/jaxb2ruby/template.rb +33 -0
- data/lib/jaxb2ruby/type_util.rb +90 -0
- data/lib/jaxb2ruby/version.rb +3 -0
- data/lib/jaxb2ruby/xjc.rb +59 -0
- data/lib/templates/happymapper.erb +39 -0
- data/lib/templates/roxml.erb +42 -0
- data/lib/templates/ruby.erb +44 -0
- data/lib/templates/util/happymapper.rb +26 -0
- data/lib/templates/util/roxml.rb +29 -0
- data/spec/converter_spec.rb +213 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/template_spec.rb +128 -0
- metadata +113 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: dc40239981acd3661e8242ccb2902b59ab764bf7
|
4
|
+
data.tar.gz: af343089fe56230f70396608b57bb5c7165b11a1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8bf71fe0df5b94ea3efe7ecd84dc076ada465b339dc20b1c3911ff6144e824329c621df25af4bfb54ca720f7d048aeb636e12eed8356bb52253b9c1bfe7d4efd
|
7
|
+
data.tar.gz: b8b1c81d1c8896ff50a33f85e9df9213f265bbdff09e837bd556b1c8bed16ddf9b1e03190bc283c5ea0af9b4c3134faa562232827a186821b904d50afcd2c31a
|
data/bin/jaxb2ruby
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
abort "jaxb2ruby must be run with jruby" unless RUBY_PLATFORM == "java"
|
4
|
+
|
5
|
+
require "optparse"
|
6
|
+
require "fileutils"
|
7
|
+
require "yaml"
|
8
|
+
require "jaxb2ruby"
|
9
|
+
|
10
|
+
include JAXB2Ruby
|
11
|
+
|
12
|
+
def mapping_option(option)
|
13
|
+
option.inject({}) do |cfg, opt|
|
14
|
+
if !opt.include?("=")
|
15
|
+
begin
|
16
|
+
cfg.merge!(YAML.load_file(opt))
|
17
|
+
rescue => e
|
18
|
+
abort "cannot load mapping file: #{e}"
|
19
|
+
end
|
20
|
+
else
|
21
|
+
url, klass = opt.split("=", 2)
|
22
|
+
abort "mapping option invalid: #{opt}" if klass.nil? or klass.strip.empty?
|
23
|
+
cfg[url] = klass
|
24
|
+
end
|
25
|
+
cfg
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
tmpl = nil
|
30
|
+
outdir = "ruby"
|
31
|
+
options = {}
|
32
|
+
parser = OptionParser.new do |opts|
|
33
|
+
opts.banner = "usage: #{File.basename($0)} [options] schema"
|
34
|
+
|
35
|
+
opts.on("-c", "--classes=MAP1[,MAP2,...]", Array, "XML Schema type to Ruby class mappings", "MAP can be a string in the form type=class or a YAML file of type/class pairs") do |typemap|
|
36
|
+
options[:typemap] = mapping_option(typemap)
|
37
|
+
end
|
38
|
+
|
39
|
+
opts.on("-h", "--help", "Show this message") do
|
40
|
+
puts opts
|
41
|
+
exit
|
42
|
+
end
|
43
|
+
|
44
|
+
opts.on("-I", "--include=DIRECTORY", "Add DIRECTORY to the load path, usefull for using custom template helpers") do |path|
|
45
|
+
$LOAD_PATH.unshift(path)
|
46
|
+
end
|
47
|
+
|
48
|
+
opts.on("-J", "--jvm=[ARG1[,ARG2,...]]", Array, "Options to pass to the JVM when calling XJC") do |opt|
|
49
|
+
(options[:jvm] ||= []).concat(opt)
|
50
|
+
end
|
51
|
+
|
52
|
+
opts.on("-n", "--namespace=MAP1[,MAP2,...]", Array, "XML namespace to ruby class mappings", "MAP can be a string in the form namespace=class or a YAML file of namespace/class pairs") do |ns|
|
53
|
+
options[:namespace] = mapping_option(ns)
|
54
|
+
end
|
55
|
+
|
56
|
+
opts.on("-o", "--output=DIRECTORY", "Directory to output the generated ruby classes, defaults to ruby") do |dir|
|
57
|
+
outdir = dir
|
58
|
+
end
|
59
|
+
|
60
|
+
opts.on("-t", "--template=NAME", "Template used to generate the ruby classes", "Can be a path to an ERB template or one of: roxml (default), happymapper, ruby") do |t|
|
61
|
+
tmpl = t
|
62
|
+
end
|
63
|
+
|
64
|
+
opts.on("-v", "--version", "jaxb2ruby version") do
|
65
|
+
puts "v#{JAXB2Ruby::VERSION}"
|
66
|
+
exit
|
67
|
+
end
|
68
|
+
|
69
|
+
opts.on("-w", "--wsdl", "Treat the schema as a WSDL", "Automatically set if the schema has a `.wsdl' extension") do
|
70
|
+
options[:wsdl] = true
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
parser.parse!
|
75
|
+
schema = ARGV.shift
|
76
|
+
abort parser.banner if schema.nil?
|
77
|
+
|
78
|
+
begin
|
79
|
+
template = Template.new(tmpl)
|
80
|
+
ruby_classes = Converter.convert(schema, options)
|
81
|
+
puts "outputting classes to #{outdir}"
|
82
|
+
ruby_classes.each do |klass|
|
83
|
+
puts "generating: #{klass.path}"
|
84
|
+
FileUtils.mkdir_p(File.join(outdir, klass.directory))
|
85
|
+
File.open(File.join(outdir, klass.path), "w") { |io| io.puts template.build(klass) }
|
86
|
+
end
|
87
|
+
rescue => e
|
88
|
+
puts e.backtrace.join("\n")
|
89
|
+
abort "class generation failed: #{e}"
|
90
|
+
end
|
data/lib/jaxb2ruby.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "active_support/core_ext/object/blank"
|
2
|
+
require "active_support/core_ext/string"
|
3
|
+
|
4
|
+
require "jaxb2ruby/version"
|
5
|
+
require "jaxb2ruby/classes"
|
6
|
+
require "jaxb2ruby/converter"
|
7
|
+
require "jaxb2ruby/template"
|
8
|
+
|
9
|
+
module JAXB2Ruby
|
10
|
+
RUBY_PKG_SEP = "::"
|
11
|
+
JAVA_PKG_SEP = "."
|
12
|
+
JAVA_CLASS_SEP = "$"
|
13
|
+
|
14
|
+
class Error < StandardError; end
|
15
|
+
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
|
3
|
+
module JAXB2Ruby
|
4
|
+
class ClassName < String # :nodoc:
|
5
|
+
attr :module
|
6
|
+
attr :outter_class # if java inner class, if any
|
7
|
+
attr :name # module + outter_class + basename
|
8
|
+
attr :basename
|
9
|
+
|
10
|
+
# Turn a java class name into a ruby class name, with accessors for various parts
|
11
|
+
def initialize(java_name, rubymod = nil)
|
12
|
+
pkg = java_name.split(JAVA_PKG_SEP)
|
13
|
+
pkg = rubymod ? [rubymod, ns2mod(pkg[-1])] : pkg.map { |part| ns2mod(part) }
|
14
|
+
|
15
|
+
parts = pkg.pop.split(JAVA_CLASS_SEP)
|
16
|
+
@basename = parts.pop
|
17
|
+
@outter_class = parts.join(RUBY_PKG_SEP)
|
18
|
+
@module = rubymod || pkg.join(RUBY_PKG_SEP)
|
19
|
+
@name = [@module, @outter_class, @basename].reject(&:empty?).join(RUBY_PKG_SEP)
|
20
|
+
|
21
|
+
super @name
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def ns2mod(pkg)
|
26
|
+
pkg.sub(/\A_/, "V").camelize
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Namespace < String # :nodoc:
|
31
|
+
counter = 0
|
32
|
+
@@prefixes = Hash.new { |h,ns| h[ns] = "ns#{counter+=1}".freeze }
|
33
|
+
|
34
|
+
attr :name
|
35
|
+
attr :prefix
|
36
|
+
|
37
|
+
def initialize(name)
|
38
|
+
@name = name
|
39
|
+
@prefix = @@prefixes[name]
|
40
|
+
super
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Node
|
45
|
+
attr :type
|
46
|
+
attr :name
|
47
|
+
attr :local_name
|
48
|
+
attr :namespace
|
49
|
+
attr :accessor
|
50
|
+
attr :default
|
51
|
+
|
52
|
+
def initialize(name, options = {})
|
53
|
+
@name = @local_name = name
|
54
|
+
|
55
|
+
@accessor = (options[:accessor] || name).underscore
|
56
|
+
# If this conflicts with a Java keyword it will start with an underscore
|
57
|
+
@accessor.sub!(/\A_/, "")
|
58
|
+
|
59
|
+
@namespace = options[:namespace]
|
60
|
+
@name = sprintf "%s:%s", @namespace.prefix, @local_name if @namespace
|
61
|
+
|
62
|
+
@default = options[:default]
|
63
|
+
@required = !!options[:required]
|
64
|
+
@type = options[:type]
|
65
|
+
|
66
|
+
# TODO: this isn't used. Future plans?
|
67
|
+
@array = !!options[:array]
|
68
|
+
@hash = false
|
69
|
+
|
70
|
+
# Uhhhh, I think this might need some revisiting, esp. with xsd:enumeration
|
71
|
+
if @type.is_a?(Array)
|
72
|
+
@accessor = @accessor.pluralize
|
73
|
+
|
74
|
+
if @type.one?
|
75
|
+
@array = true
|
76
|
+
@type = @type.shift
|
77
|
+
else
|
78
|
+
@hash = true
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def hash?
|
84
|
+
@hash
|
85
|
+
end
|
86
|
+
|
87
|
+
def array?
|
88
|
+
@array
|
89
|
+
end
|
90
|
+
|
91
|
+
def required?
|
92
|
+
@required
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class Attribute < Node; end
|
97
|
+
|
98
|
+
class Element < Node
|
99
|
+
attr :children
|
100
|
+
attr :attributes
|
101
|
+
|
102
|
+
def initialize(name, options = {})
|
103
|
+
super
|
104
|
+
@text = !!options[:text]
|
105
|
+
@root = !!options[:root]
|
106
|
+
@nillable = !!options[:nillable]
|
107
|
+
@children = options[:children] || []
|
108
|
+
@attributes = options[:attributes] || []
|
109
|
+
end
|
110
|
+
|
111
|
+
def nillable?
|
112
|
+
@nillable
|
113
|
+
end
|
114
|
+
|
115
|
+
def root?
|
116
|
+
@root
|
117
|
+
end
|
118
|
+
|
119
|
+
def text?
|
120
|
+
@text
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class RubyClass
|
125
|
+
extend Forwardable
|
126
|
+
|
127
|
+
attr :module
|
128
|
+
attr :outter_class
|
129
|
+
attr :superclass
|
130
|
+
attr :element
|
131
|
+
|
132
|
+
def_delegators :@type, :name, :basename, :to_s
|
133
|
+
|
134
|
+
def initialize(type, element, dependencies = nil, superclass = nil)
|
135
|
+
@type = type
|
136
|
+
@element = element
|
137
|
+
@dependencies = dependencies || []
|
138
|
+
@superclass = superclass
|
139
|
+
|
140
|
+
@module = @type.module.dup unless @type.module.empty?
|
141
|
+
@outter_class = @type.outter_class.dup unless @type.outter_class.empty?
|
142
|
+
|
143
|
+
[@module, @outter_class].each do |v|
|
144
|
+
v.extend Enumerable
|
145
|
+
|
146
|
+
# v may be NilClass
|
147
|
+
def v.each(&block)
|
148
|
+
( nil? ? [] : split(RUBY_PKG_SEP) ).each(&block)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def filename
|
154
|
+
"#{basename.underscore}.rb"
|
155
|
+
end
|
156
|
+
|
157
|
+
def directory
|
158
|
+
File.dirname(path)
|
159
|
+
end
|
160
|
+
|
161
|
+
# This class's path, for passing to +require+.
|
162
|
+
# <code>Foo::Bar::OneTwo</code> will be turned into <code>foo/bar/one_two</code>.
|
163
|
+
#
|
164
|
+
def path
|
165
|
+
@path ||= make_path(@module.to_a.concat(outter_class.to_a).push(filename))
|
166
|
+
end
|
167
|
+
|
168
|
+
# Paths for all of this class's dependencies, for passing to +require+.
|
169
|
+
#
|
170
|
+
def requires
|
171
|
+
# p @element
|
172
|
+
# p @module
|
173
|
+
# @dependencies.each { |e| p e }
|
174
|
+
# p "-" * 20
|
175
|
+
|
176
|
+
@requires ||= @dependencies.map { |e| make_path(e.split(RUBY_PKG_SEP)) }.sort.uniq
|
177
|
+
end
|
178
|
+
|
179
|
+
private
|
180
|
+
def make_path(modules)
|
181
|
+
modules.map { |name| name.underscore }.join("/")
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<?xml version="1.0"?>
|
2
|
+
<jxb:bindings version="1.0"
|
3
|
+
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
4
|
+
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
|
5
|
+
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
|
6
|
+
jxb:extensionBindingPrefixes="xjc">
|
7
|
+
<jxb:globalBindings>
|
8
|
+
<!--
|
9
|
+
* Creates a type instead of a JAXBElement for xsd:choice elements
|
10
|
+
* Pluralizes names (we do this anyways in the Ruby code)
|
11
|
+
-->
|
12
|
+
<xjc:simple />
|
13
|
+
<!-- No inherritance when creating elements with a restriction base type -->
|
14
|
+
<!-- <xjc:treatRestrictionLikeNewType /> -->
|
15
|
+
</jxb:globalBindings>
|
16
|
+
</jxb:bindings>
|
@@ -0,0 +1,250 @@
|
|
1
|
+
require "find"
|
2
|
+
require "fileutils"
|
3
|
+
require "java"
|
4
|
+
|
5
|
+
require "jaxb2ruby/xjc"
|
6
|
+
require "jaxb2ruby/type_util"
|
7
|
+
|
8
|
+
module JAXB2Ruby
|
9
|
+
class Converter # :nodoc:
|
10
|
+
XML_NULL = "\u0000"
|
11
|
+
XML_ANNOT_DEFAULT = "##default"
|
12
|
+
|
13
|
+
def self.convert(schema, options = {})
|
14
|
+
new(schema, options).convert
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(schema, options = {})
|
18
|
+
raise ArgumentError, "cannot access schema: #{schema}" unless File.file?(schema) and File.readable?(schema)
|
19
|
+
@xjc = XJC.new(schema, :wsdl => !!options[:wsdl], :jvm => options[:jvm])
|
20
|
+
|
21
|
+
@namespace = options[:namespace] || {}
|
22
|
+
raise ArgumentError, "namespace mapping must be a Hash" unless @namespace.is_a?(Hash)
|
23
|
+
|
24
|
+
@typemap = TypeUtil.new(options[:typemap])
|
25
|
+
end
|
26
|
+
|
27
|
+
def convert
|
28
|
+
create_java_classes
|
29
|
+
create_ruby_classes
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
def create_java_classes
|
34
|
+
@classes = @xjc.execute
|
35
|
+
end
|
36
|
+
|
37
|
+
def create_ruby_classes
|
38
|
+
java_classes = find_java_classes(@classes)
|
39
|
+
raise Error, "no classes were generated from the schema" if java_classes.empty?
|
40
|
+
|
41
|
+
$CLASSPATH << @classes unless $CLASSPATH.include?(@classes)
|
42
|
+
extract_classes(java_classes)
|
43
|
+
rescue IOError, SystemCallError => e
|
44
|
+
raise Error, "failed to generate ruby class: #{e}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def find_java_classes(root)
|
48
|
+
# Without this, parent dir removal below could leave "/" at the start of a non-root path
|
49
|
+
# why do we need exapand though..?
|
50
|
+
root = File.expand_path(root) << "/" unless root.end_with?("/")
|
51
|
+
classes = []
|
52
|
+
|
53
|
+
Find.find(root) do |path|
|
54
|
+
if File.file?(path) && File.extname(path) == ".class"
|
55
|
+
path[root] = "" # Want com/example/Class not root/com/example/Class
|
56
|
+
classes << path
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
classes.map { |path| java_name_from_path(path) }
|
61
|
+
end
|
62
|
+
|
63
|
+
def java_name_from_path(path)
|
64
|
+
klass = path.split(%r{/}).join(".")
|
65
|
+
klass[%r{\.class\Z}] = ""
|
66
|
+
klass
|
67
|
+
end
|
68
|
+
|
69
|
+
def extract_namespace(annot)
|
70
|
+
ns = annot.namespace
|
71
|
+
Namespace.new(ns) unless ns.blank? or ns == XML_ANNOT_DEFAULT
|
72
|
+
end
|
73
|
+
|
74
|
+
def find_namespace(klass)
|
75
|
+
annot = klass.annotation(javax.xml.bind.annotation.XmlRootElement.java_class) || klass.annotation(javax.xml.bind.annotation.XmlType.java_class)
|
76
|
+
return unless annot
|
77
|
+
|
78
|
+
# if klass is an inner class the namespace will be on the outter class (enclosing_class).
|
79
|
+
annot.namespace == XML_ANNOT_DEFAULT && klass.enclosing_class ?
|
80
|
+
find_namespace(klass.enclosing_class) :
|
81
|
+
annot.namespace
|
82
|
+
end
|
83
|
+
|
84
|
+
def translate_type(klass)
|
85
|
+
# Won't work for extract_class() as it expects an instance but this should be split anyways
|
86
|
+
return "Object" if klass.java_kind_of?(java.lang.reflect.WildcardType)
|
87
|
+
|
88
|
+
type = @typemap.java2ruby(klass.name)
|
89
|
+
return type if type
|
90
|
+
return "String" if klass.enum?
|
91
|
+
|
92
|
+
# create_class_name(klass)
|
93
|
+
modname = @namespace[find_namespace(klass)]
|
94
|
+
ClassName.new(klass.name, modname)
|
95
|
+
end
|
96
|
+
|
97
|
+
def resolve_type(field)
|
98
|
+
return :ID if field.annotation_present?(javax.xml.bind.annotation.XmlID.java_class)
|
99
|
+
return :IDREF if field.annotation_present?(javax.xml.bind.annotation.XmlIDREF.java_class)
|
100
|
+
|
101
|
+
annot = field.get_annotation(javax.xml.bind.annotation.XmlSchemaType.java_class)
|
102
|
+
return @typemap.schema2ruby(annot.name) if annot.respond_to?(:name)
|
103
|
+
|
104
|
+
# Limited type checking here (but still maybe too much? it's a tad ugly)
|
105
|
+
# should be good enough for List<JAXBElement<Object>> and its variants
|
106
|
+
if field.type.name == "java.util.List"
|
107
|
+
resolved_type = []
|
108
|
+
type = field.generic_type
|
109
|
+
|
110
|
+
if type.java_kind_of?(java.lang.reflect.ParameterizedType)
|
111
|
+
type = type.actual_type_arguments.first
|
112
|
+
|
113
|
+
if type.java_kind_of?(java.lang.reflect.ParameterizedType)
|
114
|
+
resolved_type << translate_type(type.actual_type_arguments.first)
|
115
|
+
# elsif type.java_kind_of?(java.lang.reflect.WildcardType)
|
116
|
+
# type.get_upper_bounds.each do |lower|
|
117
|
+
# end
|
118
|
+
# type.get_lower_bounds.each do |upper|
|
119
|
+
# end
|
120
|
+
else
|
121
|
+
resolved_type << translate_type(type)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
return resolved_type
|
126
|
+
end
|
127
|
+
|
128
|
+
translate_type(field.type)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Create a RubyClass for the given Java class.
|
132
|
+
def extract_class(klass)
|
133
|
+
# Here we expect type to be a ClassName but translate_type can return a String!
|
134
|
+
# type = create_class_name(klass)
|
135
|
+
type = translate_type(klass)
|
136
|
+
element = extract_element(klass)
|
137
|
+
|
138
|
+
dependencies = []
|
139
|
+
#dependencies << type.parent_class if type.parent_class
|
140
|
+
|
141
|
+
superclass = nil
|
142
|
+
if klass.superclass.name != "java.lang.Object"
|
143
|
+
# create_class_name(klass.superclass)
|
144
|
+
superclass = translate_type(klass.superclass)
|
145
|
+
dependencies << superclass
|
146
|
+
end
|
147
|
+
|
148
|
+
(element.children + element.attributes).each do |node|
|
149
|
+
# If a node's type isn't predefined, it must be an XML mapped class
|
150
|
+
dependencies << node.type if !@typemap.schema_ruby_types.include?(node.type)
|
151
|
+
end
|
152
|
+
#p "-" * 20
|
153
|
+
|
154
|
+
RubyClass.new(type, element, dependencies, superclass)
|
155
|
+
end
|
156
|
+
|
157
|
+
# Create elements and attributes from the given Java class' fields
|
158
|
+
def extract_elements_nodes(klass)
|
159
|
+
nodes = { :attributes => [], :children => [] }
|
160
|
+
|
161
|
+
klass.declared_fields.each do |field|
|
162
|
+
if field.annotation_present?(javax.xml.bind.annotation.XmlValue.java_class) || field.annotation_present?(javax.xml.bind.annotation.XmlMixed.java_class)
|
163
|
+
nodes[:text] = true
|
164
|
+
next if field.annotation_present?(javax.xml.bind.annotation.XmlValue.java_class)
|
165
|
+
end
|
166
|
+
|
167
|
+
childopts = { :type => resolve_type(field), :accessor => field.name }
|
168
|
+
#childopts[:type] = type # unless Array(type).first == "Object"
|
169
|
+
childname = childopts[:accessor]
|
170
|
+
|
171
|
+
if annot = field.get_annotation(javax.xml.bind.annotation.XmlElement.java_class) ||
|
172
|
+
field.get_annotation(javax.xml.bind.annotation.XmlElementRef.java_class) ||
|
173
|
+
field.get_annotation(javax.xml.bind.annotation.XmlAttribute.java_class)
|
174
|
+
|
175
|
+
childopts[:namespace] = extract_namespace(annot)
|
176
|
+
childopts[:required] = annot.respond_to?(:required?) ? annot.required? : false
|
177
|
+
childopts[:nillable] = annot.respond_to?(:nillable?) ? annot.nillable? : false
|
178
|
+
|
179
|
+
childname = annot.name if annot.name != XML_ANNOT_DEFAULT
|
180
|
+
|
181
|
+
# Not all implementations support default values for attributes
|
182
|
+
if annot.respond_to?(:default_value)
|
183
|
+
childopts[:default] = annot.default_value == XML_NULL ? nil : annot.default_value
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
if field.annotation_present?(javax.xml.bind.annotation.XmlAttribute.java_class)
|
188
|
+
nodes[:attributes] << Attribute.new(childname, childopts)
|
189
|
+
else
|
190
|
+
nodes[:children] << Element.new(childname, childopts)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
nodes
|
195
|
+
end
|
196
|
+
|
197
|
+
# Create an element from a Java class, turning its fields into elements and attributes
|
198
|
+
def extract_element(klass)
|
199
|
+
#p klass
|
200
|
+
options = extract_elements_nodes(klass)
|
201
|
+
|
202
|
+
if annot = klass.get_annotation(javax.xml.bind.annotation.XmlRootElement.java_class)
|
203
|
+
name = annot.name
|
204
|
+
options[:root] = true
|
205
|
+
end
|
206
|
+
|
207
|
+
|
208
|
+
|
209
|
+
|
210
|
+
if name.blank?
|
211
|
+
annot = klass.get_annotation(javax.xml.bind.annotation.XmlType.java_class)
|
212
|
+
name = annot.name
|
213
|
+
end
|
214
|
+
|
215
|
+
name = klass.name if name.blank?
|
216
|
+
name = name.split(JAVA_CLASS_SEP).last # might be an inner class
|
217
|
+
# Should grab annot.prop_order
|
218
|
+
# annot = klass.get_annotation(javax.xml.bind.annotation.XmlType.java_class)
|
219
|
+
# annot.prop_order are java props here we have element names
|
220
|
+
# element.elements.sort_by! { |e| annot.prop_order.index }
|
221
|
+
options[:namespace] = extract_namespace(annot)
|
222
|
+
|
223
|
+
#p "name2 #{name}"
|
224
|
+
#p options
|
225
|
+
e=Element.new(name, options)
|
226
|
+
#p e.name
|
227
|
+
#p e.local_name
|
228
|
+
#p e.namespace
|
229
|
+
#p "-" * 20
|
230
|
+
e
|
231
|
+
end
|
232
|
+
|
233
|
+
def valid_class?(klass)
|
234
|
+
# Skip Enum for now, maybe forever!
|
235
|
+
# TODO: make sure this is a legit class else we can get a const error.
|
236
|
+
# For example, if someone uses a namespace that xjc translates into a /javax?/ package
|
237
|
+
!klass.enum? && klass.annotation_present?(javax.xml.bind.annotation.XmlType.java_class)
|
238
|
+
end
|
239
|
+
|
240
|
+
def extract_classes(java_classes)
|
241
|
+
ruby_classes = []
|
242
|
+
java_classes.each do |name|
|
243
|
+
klass = Java.send(name).java_class.to_java
|
244
|
+
next unless valid_class?(klass)
|
245
|
+
ruby_classes << extract_class(klass)
|
246
|
+
end
|
247
|
+
ruby_classes
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|