Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/schema_salad/java_codegen.py @ 2:6af9afd405e9 draft
"planemo upload commit 0a63dd5f4d38a1f6944587f52a8cd79874177fc1"
| author | shellac |
|---|---|
| date | Thu, 14 May 2020 14:56:58 -0400 |
| parents | 26e78fe6e8c4 |
| children |
comparison
equal
deleted
inserted
replaced
| 1:75ca89e9b81c | 2:6af9afd405e9 |
|---|---|
| 1 """Work-in-progress Java code generator for a given schema salad definition.""" | |
| 2 import os | |
| 3 import pkg_resources | |
| 4 import string | |
| 5 import shutil | |
| 6 from io import open as io_open | |
| 7 from typing import Any, Dict, List, MutableMapping, MutableSequence, Optional, Union | |
| 8 | |
| 9 from six import iteritems, itervalues | |
| 10 from six.moves import cStringIO, urllib | |
| 11 from typing_extensions import Text # pylint: disable=unused-import | |
| 12 | |
| 13 from . import schema | |
| 14 from .codegen_base import CodeGenBase, TypeDef | |
| 15 from .exceptions import SchemaException | |
| 16 from .schema import shortname | |
| 17 | |
| 18 # move to a regular typing import when Python 3.3-3.6 is no longer supported | |
| 19 | |
| 20 # experiment at providing more typed objects building a optional type that allows | |
| 21 # referencing one or a list of objects. It is useful for improving the RootLoader | |
| 22 # for simple schema with a single root loader - but doesn't help with CWL at all and | |
| 23 # may even confuse things a bit so turning these off be default. | |
| 24 USE_ONE_OR_LIST_OF_TYPES = False | |
| 25 | |
| 26 | |
| 27 def _ensure_directory_and_write(path, contents): | |
| 28 # type: (Text, Text) -> None | |
| 29 dirname = os.path.dirname(path) | |
| 30 _safe_makedirs(dirname) | |
| 31 with io_open(path, mode="w", encoding="utf-8") as f: | |
| 32 f.write(contents) | |
| 33 | |
| 34 | |
| 35 def doc_to_doc_string(doc, indent_level=0): | |
| 36 # type: (Text, int) -> Text | |
| 37 lead = " " + " " * indent_level + "* " * indent_level | |
| 38 if doc: | |
| 39 doc_str = "{}<BLOCKQUOTE>\n".format(lead) | |
| 40 doc_str += "\n".join(["{}{}".format(lead, l) for l in doc.split("\n")]) | |
| 41 doc_str += "{}</BLOCKQUOTE>".format(lead) | |
| 42 else: | |
| 43 doc_str = "" | |
| 44 return doc_str | |
| 45 | |
| 46 | |
| 47 def _safe_makedirs(path): | |
| 48 # type: (Text) -> None | |
| 49 if not os.path.exists(path): | |
| 50 os.makedirs(path) | |
| 51 | |
| 52 | |
| 53 class JavaCodeGen(CodeGenBase): | |
| 54 def __init__(self, base, target, examples): | |
| 55 # type: (Text, Optional[str], Optional[str]) -> None | |
| 56 super(JavaCodeGen, self).__init__() | |
| 57 self.base_uri = base | |
| 58 sp = urllib.parse.urlsplit(base) | |
| 59 self.examples = examples | |
| 60 self.package = ".".join( | |
| 61 list(reversed(sp.netloc.split("."))) + sp.path.strip("/").split("/") | |
| 62 ) | |
| 63 self.artifact = self.package.split(".")[-1] | |
| 64 target = target or "." | |
| 65 self.target_dir = target | |
| 66 rel_package_dir = self.package.replace(".", "/") | |
| 67 self.rel_package_dir = rel_package_dir | |
| 68 self.main_src_dir = os.path.join( | |
| 69 self.target_dir, "src", "main", "java", rel_package_dir | |
| 70 ) | |
| 71 self.test_src_dir = os.path.join( | |
| 72 self.target_dir, "src", "test", "java", rel_package_dir | |
| 73 ) | |
| 74 self.test_resources_dir = os.path.join( | |
| 75 self.target_dir, "src", "test", "resources", rel_package_dir | |
| 76 ) | |
| 77 | |
| 78 def prologue(self): # type: () -> None | |
| 79 for src_dir in [self.main_src_dir, self.test_src_dir]: | |
| 80 _safe_makedirs(src_dir) | |
| 81 | |
| 82 for primitive in itervalues(self.prims): | |
| 83 self.declare_type(primitive) | |
| 84 | |
| 85 @staticmethod | |
| 86 def property_name(name): # type: (Text) -> Text | |
| 87 avn = schema.avro_name(name) | |
| 88 return avn | |
| 89 | |
| 90 @staticmethod | |
| 91 def safe_name(name): # type: (Text) -> Text | |
| 92 avn = JavaCodeGen.property_name(name) | |
| 93 if avn in ("class", "extends", "abstract", "default", "package"): | |
| 94 # reserved words | |
| 95 avn = avn + "_" | |
| 96 return avn | |
| 97 | |
| 98 def interface_name(self, n): | |
| 99 # type: (Text) -> Text | |
| 100 return self.safe_name(n) | |
| 101 | |
| 102 def begin_class( | |
| 103 self, | |
| 104 classname, # type: Text | |
| 105 extends, # type: MutableSequence[Text] | |
| 106 doc, # type: Text | |
| 107 abstract, # type: bool | |
| 108 field_names, # type: MutableSequence[Text] | |
| 109 idfield, # type: Text | |
| 110 ): # type: (...) -> None | |
| 111 cls = self.interface_name(classname) | |
| 112 self.current_class = cls | |
| 113 self.current_class_is_abstract = abstract | |
| 114 self.current_loader = cStringIO() | |
| 115 self.current_fieldtypes = {} # type: Dict[Text, TypeDef] | |
| 116 self.current_fields = cStringIO() | |
| 117 interface_doc_str = u"* Auto-generated interface for <I>%s</I><BR>" % classname | |
| 118 if not abstract: | |
| 119 implemented_by = u"This interface is implemented by {{@link {}Impl}}<BR>" | |
| 120 interface_doc_str += implemented_by.format(cls) | |
| 121 interface_doc_str += doc_to_doc_string(doc) | |
| 122 class_doc_str = u"* Auto-generated class implementation for <I>{}</I><BR>".format( | |
| 123 classname | |
| 124 ) | |
| 125 class_doc_str += doc_to_doc_string(doc) | |
| 126 with open(os.path.join(self.main_src_dir, "{}.java".format(cls)), "w") as f: | |
| 127 | |
| 128 if extends: | |
| 129 ext = ( | |
| 130 "extends " | |
| 131 + ", ".join(self.interface_name(e) for e in extends) | |
| 132 + ", Savable" | |
| 133 ) | |
| 134 else: | |
| 135 ext = "extends Savable" | |
| 136 f.write( | |
| 137 """package {package}; | |
| 138 | |
| 139 import {package}.utils.Savable; | |
| 140 | |
| 141 /** | |
| 142 {interface_doc_str} | |
| 143 */ | |
| 144 public interface {cls} {ext} {{""".format( | |
| 145 package=self.package, | |
| 146 cls=cls, | |
| 147 ext=ext, | |
| 148 interface_doc_str=interface_doc_str, | |
| 149 ) | |
| 150 ) | |
| 151 | |
| 152 if self.current_class_is_abstract: | |
| 153 return | |
| 154 | |
| 155 with open(os.path.join(self.main_src_dir, "{}Impl.java".format(cls)), "w") as f: | |
| 156 f.write( | |
| 157 """package {package}; | |
| 158 | |
| 159 import {package}.utils.LoaderInstances; | |
| 160 import {package}.utils.LoadingOptions; | |
| 161 import {package}.utils.LoadingOptionsBuilder; | |
| 162 import {package}.utils.SavableImpl; | |
| 163 import {package}.utils.ValidationException; | |
| 164 | |
| 165 /** | |
| 166 {class_doc_str} | |
| 167 */ | |
| 168 public class {cls}Impl extends SavableImpl implements {cls} {{ | |
| 169 private LoadingOptions loadingOptions_ = new LoadingOptionsBuilder().build(); | |
| 170 private java.util.Map<String, Object> extensionFields_ = | |
| 171 new java.util.HashMap<String, Object>(); | |
| 172 """.format( | |
| 173 package=self.package, cls=cls, class_doc_str=class_doc_str | |
| 174 ) | |
| 175 ) | |
| 176 self.current_loader.write( | |
| 177 """ | |
| 178 /** | |
| 179 * Used by {{@link {package}.utils.RootLoader}} to construct instances of {cls}Impl. | |
| 180 * | |
| 181 * @param __doc_ Document fragment to load this record object from (presumably a | |
| 182 {{@link java.util.Map}}). | |
| 183 * @param __baseUri_ Base URI to generate child document IDs against. | |
| 184 * @param __loadingOptions Context for loading URIs and populating objects. | |
| 185 * @param __docRoot_ ID at this position in the document (if available) (maybe?) | |
| 186 * @throws ValidationException If the document fragment is not a {{@link java.util.Map}} | |
| 187 * or validation of fields fails. | |
| 188 */ | |
| 189 public {cls}Impl( | |
| 190 final Object __doc_, | |
| 191 final String __baseUri_, | |
| 192 LoadingOptions __loadingOptions, | |
| 193 final String __docRoot_) {{ | |
| 194 super(__doc_, __baseUri_, __loadingOptions, __docRoot_); | |
| 195 // Prefix plumbing variables with '__' to reduce likelihood of collision with | |
| 196 // generated names. | |
| 197 String __baseUri = __baseUri_; | |
| 198 String __docRoot = __docRoot_; | |
| 199 if (!(__doc_ instanceof java.util.Map)) {{ | |
| 200 throw new ValidationException("{cls}Impl called on non-map"); | |
| 201 }} | |
| 202 final java.util.Map<String, Object> __doc = (java.util.Map<String, Object>) __doc_; | |
| 203 final java.util.List<ValidationException> __errors = | |
| 204 new java.util.ArrayList<ValidationException>(); | |
| 205 if (__loadingOptions != null) {{ | |
| 206 this.loadingOptions_ = __loadingOptions; | |
| 207 }} | |
| 208 """.format( | |
| 209 cls=cls, package=self.package | |
| 210 ) | |
| 211 ) | |
| 212 | |
| 213 def end_class(self, classname, field_names): | |
| 214 # type: (Text, List[Text]) -> None | |
| 215 with open( | |
| 216 os.path.join(self.main_src_dir, "{}.java".format(self.current_class)), "a" | |
| 217 ) as f: | |
| 218 f.write( | |
| 219 """ | |
| 220 } | |
| 221 """ | |
| 222 ) | |
| 223 if self.current_class_is_abstract: | |
| 224 return | |
| 225 | |
| 226 self.current_loader.write( | |
| 227 """ if (!__errors.isEmpty()) { | |
| 228 throw new ValidationException("Trying 'RecordField'", __errors); | |
| 229 } | |
| 230 """ | |
| 231 ) | |
| 232 for fieldname in field_names: | |
| 233 fieldtype = self.current_fieldtypes.get(fieldname) | |
| 234 if fieldtype is None: | |
| 235 continue | |
| 236 self.current_loader.write( | |
| 237 """ this.{safename} = ({type}) {safename}; | |
| 238 """.format( | |
| 239 safename=self.safe_name(fieldname), type=fieldtype.instance_type | |
| 240 ) | |
| 241 ) | |
| 242 | |
| 243 self.current_loader.write(""" }""") | |
| 244 | |
| 245 with open( | |
| 246 os.path.join(self.main_src_dir, "{}Impl.java".format(self.current_class)), | |
| 247 "a", | |
| 248 ) as f: | |
| 249 f.write(self.current_fields.getvalue()) | |
| 250 f.write(self.current_loader.getvalue()) | |
| 251 f.write( | |
| 252 """ | |
| 253 } | |
| 254 """ | |
| 255 ) | |
| 256 | |
| 257 prims = { | |
| 258 u"http://www.w3.org/2001/XMLSchema#string": TypeDef( | |
| 259 instance_type="String", | |
| 260 init="new PrimitiveLoader<String>(String.class)", | |
| 261 name="StringInstance", | |
| 262 loader_type="Loader<String>", | |
| 263 ), | |
| 264 u"http://www.w3.org/2001/XMLSchema#int": TypeDef( | |
| 265 instance_type="Integer", | |
| 266 init="new PrimitiveLoader<Integer>(Integer.class)", | |
| 267 name="IntegerInstance", | |
| 268 loader_type="Loader<Integer>", | |
| 269 ), | |
| 270 u"http://www.w3.org/2001/XMLSchema#long": TypeDef( | |
| 271 instance_type="Long", | |
| 272 name="LongInstance", | |
| 273 loader_type="Loader<Long>", | |
| 274 init="new PrimitiveLoader<Long>(Long.class)", | |
| 275 ), | |
| 276 u"http://www.w3.org/2001/XMLSchema#float": TypeDef( | |
| 277 instance_type="Float", | |
| 278 name="FloatInstance", | |
| 279 loader_type="Loader<Float>", | |
| 280 init="new PrimitiveLoader<Float>(Float.class)", | |
| 281 ), | |
| 282 u"http://www.w3.org/2001/XMLSchema#double": TypeDef( | |
| 283 instance_type="Double", | |
| 284 name="DoubleInstance", | |
| 285 loader_type="Loader<Double>", | |
| 286 init="new PrimitiveLoader<Double>(Double.class)", | |
| 287 ), | |
| 288 u"http://www.w3.org/2001/XMLSchema#boolean": TypeDef( | |
| 289 instance_type="Boolean", | |
| 290 name="BooleanInstance", | |
| 291 loader_type="Loader<Boolean>", | |
| 292 init="new PrimitiveLoader<Boolean>(Boolean.class)", | |
| 293 ), | |
| 294 u"https://w3id.org/cwl/salad#null": TypeDef( | |
| 295 instance_type="Object", | |
| 296 name="NullInstance", | |
| 297 loader_type="Loader<Object>", | |
| 298 init="new NullLoader()", | |
| 299 ), | |
| 300 u"https://w3id.org/cwl/salad#Any": TypeDef( | |
| 301 instance_type="Object", | |
| 302 name="AnyInstance", | |
| 303 init="new AnyLoader()", | |
| 304 loader_type="Loader<Object>", | |
| 305 ), | |
| 306 } | |
| 307 | |
| 308 def type_loader(self, type_declaration): | |
| 309 # type: (Union[List[Any], Dict[Text, Any], Text]) -> TypeDef | |
| 310 if isinstance(type_declaration, MutableSequence): | |
| 311 sub = [self.type_loader(i) for i in type_declaration] | |
| 312 if len(sub) < 2: | |
| 313 return sub[0] | |
| 314 | |
| 315 if len(sub) == 2: | |
| 316 type_1 = sub[0] | |
| 317 type_2 = sub[1] | |
| 318 type_1_name = type_1.name | |
| 319 type_2_name = type_2.name | |
| 320 if type_1_name == "NullInstance" or type_2_name == "NullInstance": | |
| 321 non_null_type = type_1 if type_1.name != "NullInstance" else type_2 | |
| 322 return self.declare_type( | |
| 323 TypeDef( | |
| 324 instance_type="java.util.Optional<{}>".format( | |
| 325 non_null_type.instance_type | |
| 326 ), | |
| 327 init="new OptionalLoader({})".format(non_null_type.name), | |
| 328 name="optional_{}".format(non_null_type.name), | |
| 329 loader_type="Loader<java.util.Optional<{}>>".format( | |
| 330 non_null_type.instance_type | |
| 331 ), | |
| 332 ) | |
| 333 ) | |
| 334 if ( | |
| 335 type_1_name == "array_of_{}".format(type_2_name) | |
| 336 or type_2_name == "array_of_{}".format(type_1_name) | |
| 337 ) and USE_ONE_OR_LIST_OF_TYPES: | |
| 338 if type_1_name == "array_of_{}".format(type_2_name): | |
| 339 single_type = type_2 | |
| 340 array_type = type_1 | |
| 341 else: | |
| 342 single_type = type_1 | |
| 343 array_type = type_2 | |
| 344 fqclass = "{}.{}".format(self.package, single_type.instance_type) | |
| 345 return self.declare_type( | |
| 346 TypeDef( | |
| 347 instance_type="{}.utils.OneOrListOf<{}>".format( | |
| 348 self.package, fqclass | |
| 349 ), | |
| 350 init="new OneOrListOfLoader<{}>({}, {})".format( | |
| 351 fqclass, single_type.name, array_type.name | |
| 352 ), | |
| 353 name="one_or_array_of_{}".format(single_type.name), | |
| 354 loader_type="Loader<{}.utils.OneOrListOf<{}>>".format( | |
| 355 self.package, fqclass | |
| 356 ), | |
| 357 ) | |
| 358 ) | |
| 359 return self.declare_type( | |
| 360 TypeDef( | |
| 361 instance_type="Object", | |
| 362 init="new UnionLoader(new Loader[] {{ {} }})".format( | |
| 363 ", ".join(s.name for s in sub) | |
| 364 ), | |
| 365 name="union_of_{}".format("_or_".join(s.name for s in sub)), | |
| 366 loader_type="Loader<Object>", | |
| 367 ) | |
| 368 ) | |
| 369 if isinstance(type_declaration, MutableMapping): | |
| 370 if type_declaration["type"] in ( | |
| 371 "array", | |
| 372 "https://w3id.org/cwl/salad#array", | |
| 373 ): | |
| 374 i = self.type_loader(type_declaration["items"]) | |
| 375 return self.declare_type( | |
| 376 TypeDef( | |
| 377 # special doesn't work out with subclassing, gotta be more clever | |
| 378 # instance_type="List<{}>".format(i.instance_type), | |
| 379 instance_type="java.util.List<Object>", | |
| 380 name="array_of_{}".format(i.name), | |
| 381 init="new ArrayLoader({})".format(i.name), | |
| 382 loader_type="Loader<java.util.List<{}>>".format( | |
| 383 i.instance_type | |
| 384 ), | |
| 385 ) | |
| 386 ) | |
| 387 if type_declaration["type"] in ("enum", "https://w3id.org/cwl/salad#enum"): | |
| 388 return self.type_loader_enum(type_declaration) | |
| 389 if type_declaration["type"] in ( | |
| 390 "record", | |
| 391 "https://w3id.org/cwl/salad#record", | |
| 392 ): | |
| 393 is_abstract = type_declaration.get("abstract", False) | |
| 394 fqclass = "{}.{}".format( | |
| 395 self.package, self.safe_name(type_declaration["name"]) | |
| 396 ) | |
| 397 return self.declare_type( | |
| 398 TypeDef( | |
| 399 instance_type=self.safe_name(type_declaration["name"]), | |
| 400 name=self.safe_name(type_declaration["name"]), | |
| 401 init="new RecordLoader<{clazz}>({clazz}{ext}.class)".format( | |
| 402 clazz=fqclass, ext="Impl" if not is_abstract else "", | |
| 403 ), | |
| 404 loader_type="Loader<{}>".format(fqclass), | |
| 405 ) | |
| 406 ) | |
| 407 raise SchemaException("wft {}".format(type_declaration["type"])) | |
| 408 if type_declaration in self.prims: | |
| 409 return self.prims[type_declaration] | |
| 410 return self.collected_types[self.safe_name(type_declaration)] | |
| 411 | |
| 412 def type_loader_enum(self, type_declaration): | |
| 413 # type: (Dict[Text, Any]) -> TypeDef | |
| 414 symbols = [self.property_name(sym) for sym in type_declaration["symbols"]] | |
| 415 for sym in symbols: | |
| 416 self.add_vocab(shortname(sym), sym) | |
| 417 clazz = self.safe_name(type_declaration["name"]) | |
| 418 symbols_decl = 'new String[] {{"{}"}}'.format( | |
| 419 '", "'.join(sym for sym in symbols) | |
| 420 ) | |
| 421 enum_path = os.path.join(self.main_src_dir, "{}.java".format(clazz)) | |
| 422 with open(enum_path, "w") as f: | |
| 423 f.write( | |
| 424 """package {package}; | |
| 425 | |
| 426 import {package}.utils.ValidationException; | |
| 427 | |
| 428 public enum {clazz} {{ | |
| 429 """.format( | |
| 430 package=self.package, clazz=clazz | |
| 431 ) | |
| 432 ) | |
| 433 for i, sym in enumerate(symbols): | |
| 434 suffix = "," if i < (len(symbols) - 1) else ";" | |
| 435 const = self.safe_name(sym).replace("-", "_").replace(".", "_").upper() | |
| 436 f.write( | |
| 437 """ {const}("{val}"){suffix}\n""".format( | |
| 438 const=const, val=sym, suffix=suffix | |
| 439 ) | |
| 440 ) | |
| 441 f.write( | |
| 442 """ | |
| 443 private static String[] symbols = {symbols_decl}; | |
| 444 private String docVal; | |
| 445 | |
| 446 private {clazz}(final String docVal) {{ | |
| 447 this.docVal = docVal; | |
| 448 }} | |
| 449 | |
| 450 public static {clazz} fromDocumentVal(final String docVal) {{ | |
| 451 for(final {clazz} val : {clazz}.values()) {{ | |
| 452 if(val.docVal.equals(docVal)) {{ | |
| 453 return val; | |
| 454 }} | |
| 455 }} | |
| 456 throw new ValidationException(String.format("Expected one of %s", {clazz}.symbols, docVal)); | |
| 457 }} | |
| 458 }} | |
| 459 """.format( | |
| 460 clazz=clazz, symbols_decl=symbols_decl | |
| 461 ) | |
| 462 ) | |
| 463 return self.declare_type( | |
| 464 TypeDef( | |
| 465 instance_type=clazz, | |
| 466 name=self.safe_name(type_declaration["name"]), | |
| 467 loader_type="Loader<{clazz}>".format(clazz=clazz), | |
| 468 init="new EnumLoader({clazz}.class)".format(clazz=clazz), | |
| 469 ) | |
| 470 ) | |
| 471 | |
| 472 def declare_field(self, name, fieldtype, doc, optional): | |
| 473 # type: (Text, TypeDef, Text, bool) -> None | |
| 474 fieldname = name | |
| 475 property_name = self.property_name(fieldname) | |
| 476 cap_case_property_name = property_name[0].upper() + property_name[1:] | |
| 477 if cap_case_property_name == "Class": | |
| 478 cap_case_property_name = "Class_" | |
| 479 | |
| 480 safename = self.safe_name(fieldname) | |
| 481 self.current_fieldtypes[property_name] = fieldtype | |
| 482 getter_doc_str = """ /** | |
| 483 * Getter for property <I>{fieldname}</I><BR> | |
| 484 {field_doc_str} | |
| 485 */ | |
| 486 """.format( | |
| 487 fieldname=fieldname, field_doc_str=doc_to_doc_string(doc, indent_level=1) | |
| 488 ) | |
| 489 with open( | |
| 490 os.path.join(self.main_src_dir, "{}.java".format(self.current_class)), "a" | |
| 491 ) as f: | |
| 492 f.write( | |
| 493 """ | |
| 494 {getter_doc_str} | |
| 495 {type} get{capfieldname}();""".format( | |
| 496 getter_doc_str=getter_doc_str, | |
| 497 capfieldname=cap_case_property_name, | |
| 498 type=fieldtype.instance_type, | |
| 499 ) | |
| 500 ) | |
| 501 | |
| 502 if self.current_class_is_abstract: | |
| 503 return | |
| 504 | |
| 505 self.current_fields.write( | |
| 506 """ | |
| 507 private {type} {safename}; | |
| 508 | |
| 509 {getter_doc_str} | |
| 510 public {type} get{capfieldname}() {{ | |
| 511 return this.{safename}; | |
| 512 }} | |
| 513 """.format( | |
| 514 safename=safename, | |
| 515 capfieldname=cap_case_property_name, | |
| 516 getter_doc_str=getter_doc_str, | |
| 517 type=fieldtype.instance_type, | |
| 518 ) | |
| 519 ) | |
| 520 | |
| 521 self.current_loader.write( | |
| 522 """ {type} {safename}; | |
| 523 """.format( | |
| 524 type=fieldtype.instance_type, safename=safename | |
| 525 ) | |
| 526 ) | |
| 527 if optional: | |
| 528 self.current_loader.write( | |
| 529 """ | |
| 530 if (__doc.containsKey("{fieldname}")) {{ | |
| 531 """.format( | |
| 532 fieldname=property_name | |
| 533 ) | |
| 534 ) | |
| 535 spc = " " | |
| 536 else: | |
| 537 spc = "" | |
| 538 | |
| 539 self.current_loader.write( | |
| 540 """{spc} try {{ | |
| 541 {spc} {safename} = | |
| 542 {spc} LoaderInstances | |
| 543 {spc} .{fieldtype} | |
| 544 {spc} .loadField(__doc.get("{fieldname}"), __baseUri, __loadingOptions); | |
| 545 {spc} }} catch (ValidationException e) {{ | |
| 546 {spc} {safename} = null; // won't be used but prevents compiler from complaining. | |
| 547 {spc} final String __message = "the `{fieldname}` field is not valid because:"; | |
| 548 {spc} __errors.add(new ValidationException(__message, e)); | |
| 549 {spc} }} | |
| 550 """.format( | |
| 551 fieldtype=fieldtype.name, | |
| 552 safename=safename, | |
| 553 fieldname=property_name, | |
| 554 spc=spc, | |
| 555 ) | |
| 556 ) | |
| 557 | |
| 558 if optional: | |
| 559 self.current_loader.write( | |
| 560 """ | |
| 561 }} else {{ | |
| 562 {safename} = null; | |
| 563 }} | |
| 564 """.format( | |
| 565 safename=safename | |
| 566 ) | |
| 567 ) | |
| 568 | |
| 569 def declare_id_field(self, name, fieldtype, doc, optional): | |
| 570 # type: (Text, TypeDef, Text, bool) -> None | |
| 571 if self.current_class_is_abstract: | |
| 572 return | |
| 573 | |
| 574 self.declare_field(name, fieldtype, doc, True) | |
| 575 if optional: | |
| 576 set_uri = """ | |
| 577 if ({safename} == null) {{ | |
| 578 if (__docRoot != null) {{ | |
| 579 {safename} = java.util.Optional.of(__docRoot); | |
| 580 }} else {{ | |
| 581 {safename} = java.util.Optional.of("_:" + java.util.UUID.randomUUID().toString()); | |
| 582 }} | |
| 583 }} | |
| 584 __baseUri = (String) {safename}.orElse(null); | |
| 585 """ | |
| 586 else: | |
| 587 set_uri = """ | |
| 588 if ({safename} == null) {{ | |
| 589 if (__docRoot != null) {{ | |
| 590 {safename} = __docRoot; | |
| 591 }} else {{ | |
| 592 throw new ValidationException("Missing {fieldname}"); | |
| 593 }} | |
| 594 }} | |
| 595 __baseUri = (String) {safename}; | |
| 596 """ | |
| 597 self.current_loader.write( | |
| 598 set_uri.format(safename=self.safe_name(name), fieldname=shortname(name)) | |
| 599 ) | |
| 600 | |
| 601 def uri_loader(self, inner, scoped_id, vocab_term, ref_scope): | |
| 602 # type: (TypeDef, bool, bool, Union[int, None]) -> TypeDef | |
| 603 assert inner is not None | |
| 604 instance_type = inner.instance_type or "Object" | |
| 605 return self.declare_type( | |
| 606 TypeDef( | |
| 607 instance_type=instance_type, # ? | |
| 608 name="uri_{}_{}_{}_{}".format( | |
| 609 inner.name, scoped_id, vocab_term, ref_scope | |
| 610 ), | |
| 611 init="new UriLoader({}, {}, {}, {})".format( | |
| 612 inner.name, | |
| 613 self.to_java(scoped_id), | |
| 614 self.to_java(vocab_term), | |
| 615 self.to_java(ref_scope), | |
| 616 ), | |
| 617 is_uri=True, | |
| 618 scoped_id=scoped_id, | |
| 619 ref_scope=ref_scope, | |
| 620 loader_type="Loader<{}>".format(instance_type), | |
| 621 ) | |
| 622 ) | |
| 623 | |
| 624 def idmap_loader(self, field, inner, map_subject, map_predicate): | |
| 625 # type: (Text, TypeDef, Text, Union[Text, None]) -> TypeDef | |
| 626 assert inner is not None | |
| 627 instance_type = inner.instance_type or "Object" | |
| 628 return self.declare_type( | |
| 629 TypeDef( | |
| 630 instance_type=instance_type, | |
| 631 name="idmap_{}_{}".format(self.safe_name(field), inner.name), | |
| 632 init='new IdMapLoader({}, "{}", "{}")'.format( | |
| 633 inner.name, map_subject, map_predicate | |
| 634 ), | |
| 635 loader_type="Loader<{}>".format(instance_type), | |
| 636 ) | |
| 637 ) | |
| 638 | |
| 639 def typedsl_loader(self, inner, ref_scope): | |
| 640 # type: (TypeDef, Union[int, None]) -> TypeDef | |
| 641 assert inner is not None | |
| 642 instance_type = inner.instance_type or "Object" | |
| 643 return self.declare_type( | |
| 644 TypeDef( | |
| 645 instance_type=instance_type, | |
| 646 name="typedsl_{}_{}".format(inner.name, ref_scope), | |
| 647 init="new TypeDslLoader({}, {})".format(inner.name, ref_scope), | |
| 648 loader_type="Loader<{}>".format(instance_type), | |
| 649 ) | |
| 650 ) | |
| 651 | |
| 652 return inner | |
| 653 | |
| 654 def to_java(self, val): # type: (Any) -> Any | |
| 655 if val is True: | |
| 656 return "true" | |
| 657 elif val is None: | |
| 658 return "null" | |
| 659 elif val is False: | |
| 660 return "false" | |
| 661 return val | |
| 662 | |
| 663 def epilogue(self, root_loader): # type: (TypeDef) -> None | |
| 664 pd = u"This project contains Java objects and utilities " | |
| 665 pd = pd + ' auto-generated by <a href="https://github.com/' | |
| 666 pd = pd + 'common-workflow-language/schema_salad">Schema Salad</a>' | |
| 667 pd = pd + " for parsing documents corresponding to the " | |
| 668 pd = pd + str(self.base_uri) + " schema." | |
| 669 | |
| 670 template_vars = dict( | |
| 671 base_uri=self.base_uri, | |
| 672 package=self.package, | |
| 673 group_id=self.package, | |
| 674 artifact_id=self.artifact, | |
| 675 version="0.0.1-SNAPSHOT", | |
| 676 project_name=self.package, | |
| 677 project_description=pd, | |
| 678 license_name="Apache License, Version 2.0", | |
| 679 license_url="https://www.apache.org/licenses/LICENSE-2.0.txt", | |
| 680 ) # type: MutableMapping[Text, Text] | |
| 681 | |
| 682 def template_from_resource(resource): | |
| 683 # type: (str) -> string.Template | |
| 684 template_str = pkg_resources.resource_string( | |
| 685 __name__, "java/%s" % resource | |
| 686 ).decode("utf-8") | |
| 687 template = string.Template(template_str) | |
| 688 return template | |
| 689 | |
| 690 def expand_resource_template_to(resource, path): | |
| 691 # type: (str, str) -> None | |
| 692 template = template_from_resource(resource) | |
| 693 src = template.safe_substitute(template_vars) | |
| 694 _ensure_directory_and_write(path, src) | |
| 695 | |
| 696 expand_resource_template_to("pom.xml", os.path.join(self.target_dir, "pom.xml")) | |
| 697 expand_resource_template_to( | |
| 698 "gitignore", os.path.join(self.target_dir, ".gitignore") | |
| 699 ) | |
| 700 expand_resource_template_to( | |
| 701 "package.html", os.path.join(self.main_src_dir, "package.html") | |
| 702 ) | |
| 703 expand_resource_template_to( | |
| 704 "overview.html", | |
| 705 os.path.join(self.target_dir, "src", "main", "javadoc", "overview.html"), | |
| 706 ) | |
| 707 expand_resource_template_to( | |
| 708 "MANIFEST.MF", | |
| 709 os.path.join( | |
| 710 self.target_dir, "src", "main", "resources", "META-INF", "MANIFEST.MF" | |
| 711 ), | |
| 712 ) | |
| 713 expand_resource_template_to( | |
| 714 "README.md", os.path.join(self.target_dir, "README.md"), | |
| 715 ) | |
| 716 | |
| 717 vocab = "" | |
| 718 rvocab = "" | |
| 719 for k in sorted(self.vocab.keys()): | |
| 720 vocab += """ vocab.put("{}", "{}");\n""".format(k, self.vocab[k]) | |
| 721 rvocab += """ rvocab.put("{}", "{}");\n""".format(self.vocab[k], k) | |
| 722 | |
| 723 loader_instances = "" | |
| 724 for _, collected_type in iteritems(self.collected_types): | |
| 725 loader_instances += " public static {} {} = {};\n".format( | |
| 726 collected_type.loader_type, collected_type.name, collected_type.init | |
| 727 ) | |
| 728 | |
| 729 example_tests = "" | |
| 730 if self.examples: | |
| 731 _safe_makedirs(self.test_resources_dir) | |
| 732 utils_resources = os.path.join(self.test_resources_dir, "utils") | |
| 733 if os.path.exists(utils_resources): | |
| 734 shutil.rmtree(utils_resources) | |
| 735 shutil.copytree(self.examples, utils_resources) | |
| 736 for example_name in os.listdir(self.examples): | |
| 737 if example_name.startswith("valid"): | |
| 738 basename = os.path.basename(example_name).split(".", 1)[0] | |
| 739 example_tests += """ | |
| 740 @org.junit.Test | |
| 741 public void test{basename}ByString() throws Exception {{ | |
| 742 String path = java.nio.file.Paths.get(".").toAbsolutePath().normalize().toString(); | |
| 743 String baseUri = Uris.fileUri(path) + "/"; | |
| 744 java.net.URL url = getClass().getResource("{example_name}"); | |
| 745 java.nio.file.Path resPath = java.nio.file.Paths.get(url.toURI()); | |
| 746 String yaml = new String(java.nio.file.Files.readAllBytes(resPath), "UTF8"); | |
| 747 RootLoader.loadDocument(yaml, baseUri); | |
| 748 }} | |
| 749 | |
| 750 @org.junit.Test | |
| 751 public void test{basename}ByPath() throws Exception {{ | |
| 752 java.net.URL url = getClass().getResource("{example_name}"); | |
| 753 java.nio.file.Path resPath = java.nio.file.Paths.get(url.toURI()); | |
| 754 RootLoader.loadDocument(resPath); | |
| 755 }} | |
| 756 | |
| 757 @org.junit.Test | |
| 758 public void test{basename}ByMap() throws Exception {{ | |
| 759 java.net.URL url = getClass().getResource("{example_name}"); | |
| 760 java.nio.file.Path resPath = java.nio.file.Paths.get(url.toURI()); | |
| 761 String yaml = new String(java.nio.file.Files.readAllBytes(resPath), "UTF8"); | |
| 762 java.util.Map<String, Object> doc; | |
| 763 doc = (java.util.Map<String, Object>) YamlUtils.mapFromString(yaml); | |
| 764 RootLoader.loadDocument(doc); | |
| 765 }}""".format( | |
| 766 basename=basename, example_name=example_name, | |
| 767 ) | |
| 768 | |
| 769 template_args = dict( | |
| 770 package=self.package, | |
| 771 vocab=vocab, | |
| 772 rvocab=rvocab, | |
| 773 loader_instances=loader_instances, | |
| 774 root_loader_name=root_loader.name, | |
| 775 root_loader_instance_type=root_loader.instance_type or "Object", | |
| 776 example_tests=example_tests, | |
| 777 ) # type: MutableMapping[Text, Text] | |
| 778 | |
| 779 util_src_dirs = { | |
| 780 "main_utils": self.main_src_dir, | |
| 781 "test_utils": self.test_src_dir, | |
| 782 } | |
| 783 for (util_src, util_target) in util_src_dirs.items(): | |
| 784 for util in pkg_resources.resource_listdir(__name__, "java/%s" % util_src): | |
| 785 src_path = os.path.join(util_target, "utils", util) | |
| 786 src_template = template_from_resource(os.path.join(util_src, util)) | |
| 787 src = src_template.safe_substitute(template_args) | |
| 788 _ensure_directory_and_write(src_path, src) |
