jaxb2ruby 0.0.1-java
Sign up to get free protection for your applications and to get access to all the features.
- 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
|