Skip to content

Commit dbfe31a

Browse files
committed
add XsJavaLocalDate as an alternative to XsDate if useJavaTime key setting in sbt is true.
1 parent a1c99e8 commit dbfe31a

File tree

10 files changed

+76
-51
lines changed

10 files changed

+76
-51
lines changed

cli/src/main/resources/scalaxb.scala.template

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package scalaxb
22

3+
import java.time.LocalDateTime
4+
5+
import javax.xml.datatype.{DatatypeFactory, XMLGregorianCalendar}
36
import scala.xml.{Node, NodeSeq, NamespaceBinding, Elem, UnprefixedAttribute, PrefixedAttribute}
4-
import javax.xml.datatype.{XMLGregorianCalendar}
57
import javax.xml.namespace.QName
68
import javax.xml.bind.DatatypeConverter
79

@@ -209,6 +211,17 @@ trait XMLStandardTypes {
209211
Helper.stringToXML(obj.toXMLFormat, namespace, elementLabel, scope)
210212
}
211213

214+
implicit lazy val __JavaDateTimeXMLFormat: XMLFormat[java.time.LocalDateTime] = new XMLFormat[LocalDateTime] {
215+
def localDateTime (d: XMLGregorianCalendar) : LocalDateTime = LocalDateTime.of(d.getYear, d.getMonth, d.getDay, d.getHour, d.getMinute, d.getSecond)
216+
def gregorianCalendar (d: LocalDateTime): XMLGregorianCalendar = DatatypeFactory.newInstance().newXMLGregorianCalendar(d.toString)
217+
218+
def reads(seq: scala.xml.NodeSeq, stack: List[ElemName]): Either[String, LocalDateTime] =
219+
implicitly[XMLFormat[XMLGregorianCalendar]].reads(seq, stack).map(localDateTime)
220+
221+
override def writes(obj: LocalDateTime, namespace: Option[String], elementLabel: Option[String], scope: NamespaceBinding, typeAttribute: Boolean): NodeSeq =
222+
implicitly[XMLFormat[XMLGregorianCalendar]].writes(gregorianCalendar(obj), namespace, elementLabel, scope, typeAttribute)
223+
}
224+
212225
implicit lazy val __GregorianCalendarXMLWriter: CanWriteXML[java.util.GregorianCalendar] = new CanWriteXML[java.util.GregorianCalendar] {
213226
def writes(obj: java.util.GregorianCalendar, namespace: Option[String], elementLabel: Option[String],
214227
scope: scala.xml.NamespaceBinding, typeAttribute: Boolean): scala.xml.NodeSeq =

cli/src/main/scala/scalaxb/compiler/Config.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ case class Config(items: Map[String, ConfigEntry]) {
8181
def symbolEncodingStrategy = get[SymbolEncoding.Strategy] getOrElse defaultSymbolEncodingStrategy
8282
def enumNameMaxLength: Int = (get[EnumNameMaxLength] getOrElse defaultEnumNameMaxLength).value
8383
def useLists: Boolean = values contains UseLists
84+
def useJavaTime: Boolean = values contains UseJavaTime
8485

8586
private def get[A <: ConfigEntry: Manifest]: Option[A] =
8687
items.get(implicitly[Manifest[A]].runtimeClass.getName).asInstanceOf[Option[A]]
@@ -158,6 +159,7 @@ object ConfigEntry {
158159
case object CapitalizeWords extends ConfigEntry
159160
case class EnumNameMaxLength(value: Int) extends ConfigEntry
160161
case object UseLists extends ConfigEntry
162+
case object UseJavaTime extends ConfigEntry
161163

162164
object SymbolEncoding {
163165
sealed abstract class Strategy(val alias: String, val description: String) extends ConfigEntry with Product with Serializable {

cli/src/main/scala/scalaxb/compiler/Module.scala

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,16 @@
2222

2323
package scalaxb.compiler
2424

25-
import java.net.{URI}
26-
import scala.xml.{Node, Elem, UnprefixedAttribute, NamespaceBinding}
27-
import scala.xml.factory.{XMLLoader}
25+
import java.net.URI
26+
27+
import scala.xml.{Elem, NamespaceBinding, Node, UnprefixedAttribute}
28+
import scala.xml.factory.XMLLoader
2829
import javax.xml.parsers.SAXParser
29-
import java.io.{File, PrintWriter, Reader, BufferedReader}
30-
import scala.collection.mutable
30+
import java.io.{BufferedReader, File, PrintWriter, Reader}
31+
3132
import scala.collection.mutable.{ListBuffer, ListMap}
3233
import ConfigEntry._
34+
import scalaxb.compiler.xsd.ParserConfig
3335

3436
object Snippet {
3537
def apply(snippets: Snippet*): Snippet =
@@ -117,7 +119,7 @@ trait Module {
117119
def includeLocations: Seq[String]
118120
def raw: RawSchema
119121
def location: URI
120-
def toSchema(context: Context): Schema
122+
def toSchema(context: Context, config: ParserConfig): Schema
121123
def swapTargetNamespace(outerNamespace: Option[String], n: Int): Importable
122124
}
123125

@@ -201,26 +203,28 @@ trait Module {
201203

202204
def processReaders[From, To](files: Seq[From], config: Config)
203205
(implicit ev: CanBeRawSchema[From, RawSchema], evTo: CanBeWriter[To]): (CompileSource[From], List[To]) = {
204-
val source = buildCompileSource(files)
206+
val source = buildCompileSource(files, config)
205207
(source, processCompileSource(source, config))
206208
}
207209

208-
def buildCompileSource[From, To](files: Seq[From])
210+
def buildCompileSource[From, To](files: Seq[From], config: Config)
209211
(implicit ev: CanBeRawSchema[From, RawSchema]): CompileSource[From] = {
210212

211213
logger.debug("%s", files.toString())
212214
val context = buildContext
213215
val importables0 = ListMap[From, Importable](files map { f =>
214216
f -> toImportable(ev.toURI(f), ev.toRawSchema(f))}: _*)
215217
val importables = ListBuffer[(Importable, From)](files map { f => importables0(f) -> f }: _*)
218+
val parserConfig = new ParserConfig
219+
parserConfig.useJavaTime = config.useJavaTime
216220
val schemas = ListMap[Importable, Schema](importables map { case (importable, file) =>
217-
val s = parse(importable, context)
221+
val s = parse(importable, context, parserConfig)
218222
(importable, s) } toSeq: _*)
219223

220224
val additionalImportables = ListMap.empty[Importable, File]
221225

222226
// recursively add missing files
223-
def addMissingFiles(): Unit = {
227+
def addMissingFiles(parserConfig: ParserConfig): Unit = {
224228
val current = (importables map {_._1}) ++ additionalImportables.keysIterator.toList
225229
// check for all dependencies before proceeding.
226230
val missings = (current flatMap { importable =>
@@ -239,12 +243,12 @@ trait Module {
239243
added = true
240244
val importable = toImportable(implicitly[CanBeRawSchema[File, RawSchema]].toURI(x),
241245
implicitly[CanBeRawSchema[File, RawSchema]].toRawSchema(x))
242-
val s = parse(importable, context)
246+
val s = parse(importable, context, parserConfig)
243247
schemas(importable) = s
244248
(importable, x) })
245-
if (added) addMissingFiles()
249+
if (added) addMissingFiles(parserConfig)
246250
}
247-
def processUnnamedIncludes(): Unit = {
251+
def processUnnamedIncludes(parserConfig: ParserConfig): Unit = {
248252
logger.debug("processUnnamedIncludes")
249253
val all = (importables.toList map {_._1}) ++ (additionalImportables.toList map {_._1})
250254
val parents: ListBuffer[Importable] = ListBuffer(all filter { !_.includeLocations.isEmpty}: _*)
@@ -270,7 +274,7 @@ trait Module {
270274
logger.debug("processUnnamedIncludes - setting %s's outer namespace to %s", x.location, tnsstr)
271275
count += 1
272276
val swap = x.swapTargetNamespace(tns, count)
273-
schemas(swap) = parse(swap, context)
277+
schemas(swap) = parse(swap, context, parserConfig)
274278
additionalImportables(swap) = new File(swap.location.getPath)
275279
used += x
276280
}
@@ -292,8 +296,8 @@ trait Module {
292296
}
293297
}
294298

295-
addMissingFiles()
296-
processUnnamedIncludes()
299+
addMissingFiles(parserConfig)
300+
processUnnamedIncludes(parserConfig)
297301
CompileSource(context, schemas, importables, additionalImportables,
298302
importables0(files.head).targetNamespace)
299303
}
@@ -426,11 +430,11 @@ trait Module {
426430

427431
def nodeToRawSchema(node: Node): RawSchema
428432

429-
def parse(importable: Importable, context: Context): Schema
430-
= importable.toSchema(context)
433+
def parse(importable: Importable, context: Context, config: ParserConfig): Schema
434+
= importable.toSchema(context, config)
431435

432-
def parse(location: URI, in: Reader): Schema
433-
= parse(toImportable(location, readerToRawSchema(in)), buildContext)
436+
def parse(location: URI, in: Reader, config: ParserConfig): Schema
437+
= parse(toImportable(location, readerToRawSchema(in)), buildContext, config)
434438

435439
def printNodes(nodes: Seq[Node], out: PrintWriter): Unit = {
436440
import scala.xml._
@@ -487,7 +491,7 @@ trait Module {
487491
NamespaceBinding(null, outerNamespace getOrElse null, scope)
488492
def fixSeq(ns: Seq[Node]): Seq[Node] =
489493
for { node <- ns } yield node match {
490-
case elem: Elem =>
494+
case elem: Elem =>
491495
elem.copy(scope = fixScope(elem.scope),
492496
child = fixSeq(elem.child))
493497
case other => other

cli/src/main/scala/scalaxb/compiler/wsdl11/Driver.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import java.net.URI
3131

3232
import scala.xml.Node
3333
import scala.reflect.ClassTag
34-
import scalaxb.compiler.xsd.{GenProtocol, SchemaDecl, SchemaLite, XsdContext}
34+
import scalaxb.compiler.xsd.{GenProtocol, ParserConfig, SchemaDecl, SchemaLite, XsdContext}
3535

3636
import scala.util.matching.Regex
3737

@@ -166,14 +166,14 @@ class Driver extends Module { driver =>
166166
schemaLite.includes map { _.schemaLocation }
167167
}
168168

169-
def toSchema(context: Context): WsdlPair = {
169+
def toSchema(context: Context, config: ParserConfig): WsdlPair = {
170170
wsdl foreach { wsdl =>
171171
logger.debug(wsdl.toString)
172172
context.definitions += wsdl
173173
}
174174

175175
val xsd = xsdRawSchema map { x =>
176-
val schema = SchemaDecl.fromXML(x, context.xsdcontext)
176+
val schema = SchemaDecl.fromXML(x, context.xsdcontext, config)
177177
logger.debug(schema.toString)
178178
schema
179179
}

cli/src/main/scala/scalaxb/compiler/wsdl11/GenSource.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,7 @@ trait {interfaceTypeName} {{
642642
def buildPartArg(part: XPartType, selector: String): String =
643643
(part.typeValue, part.element) match {
644644
case (Some(typeValueQName), _) =>
645-
val typeSymbol = toTypeSymbol(typeValueQName)
645+
val typeSymbol = toTypeSymbol(typeValueQName, config.useJavaTime)
646646
xsdgenerator.buildArg(xsdgenerator.buildTypeName(typeSymbol), selector, Single, None)
647647
case (_, Some(elementQName)) =>
648648
val elem = xsdgenerator.elements(splitTypeName(elementQName))
@@ -718,17 +718,17 @@ trait {interfaceTypeName} {{
718718
def toParamCache(part: XPartType): ParamCache =
719719
part.typeValue map { typeValue =>
720720
val name = camelCase(part.name getOrElse "in")
721-
ParamCache(name, toTypeSymbol(typeValue), Single, false, false)
721+
ParamCache(name, toTypeSymbol(typeValue, config.useJavaTime), Single, false, false)
722722
} getOrElse {
723723
part.element map { element =>
724724
val param = xsdgenerator.buildParam(xsdgenerator.elements(splitTypeName(element))) map {camelCase}
725725
ParamCache(param.toParamName, param.typeSymbol, param.cardinality, param.nillable, false)
726726
} getOrElse {sys.error("part does not have either type or element: " + part.toString)}
727727
}
728728

729-
def toTypeSymbol(qname: javax.xml.namespace.QName): XsTypeSymbol = {
729+
def toTypeSymbol(qname: javax.xml.namespace.QName, useJavaTime: Boolean): XsTypeSymbol = {
730730
import scalaxb.compiler.xsd.{ReferenceTypeSymbol, TypeSymbolParser}
731-
val symbol = TypeSymbolParser.fromQName(qname)
731+
val symbol = TypeSymbolParser.fromQName(qname, useJavaTime)
732732
symbol match {
733733
case symbol: ReferenceTypeSymbol =>
734734
val (namespace, typeName) = splitTypeName(qname)

cli/src/main/scala/scalaxb/compiler/xsd/Decl.scala

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class ParserConfig {
5959
var targetNamespace: Option[String] = None
6060
var elementQualifiedDefault: Boolean = false
6161
var attributeQualifiedDefault: Boolean = false
62+
var useJavaTime: Boolean = false
6263
val topElems = mutable.ListMap.empty[String, ElemDecl]
6364
val elemList = mutable.ListBuffer.empty[ElemDecl]
6465
val topTypes = mutable.ListMap.empty[String, TypeDecl]
@@ -78,16 +79,16 @@ object TypeSymbolParser {
7879
val XML_URI = "http://www.w3.org/XML/1998/namespace"
7980

8081
def fromString(name: String, scope: NamespaceBinding, config: ParserConfig): XsTypeSymbol =
81-
fromString(splitTypeName(name, scope, config.targetNamespace))
82+
fromString(splitTypeName(name, scope, config.targetNamespace), config.useJavaTime)
8283

83-
def fromQName(qname: javax.xml.namespace.QName): XsTypeSymbol =
84-
fromString((masked.scalaxb.Helper.nullOrEmpty(qname.getNamespaceURI), qname.getLocalPart))
84+
def fromQName(qname: javax.xml.namespace.QName, useJavaTime: Boolean): XsTypeSymbol =
85+
fromString((masked.scalaxb.Helper.nullOrEmpty(qname.getNamespaceURI), qname.getLocalPart), useJavaTime)
8586

86-
def fromString(pair: (Option[String], String)): XsTypeSymbol = {
87+
def fromString(pair: (Option[String], String), useJavaTime: Boolean): XsTypeSymbol = {
8788
val (namespace, localPart) = pair
8889
namespace match {
8990
case Some(XML_SCHEMA_URI) =>
90-
if (XsTypeSymbol.toTypeSymbol.isDefinedAt(localPart)) XsTypeSymbol.toTypeSymbol(localPart)
91+
if (XsTypeSymbol.toTypeSymbol(useJavaTime).isDefinedAt(localPart)) XsTypeSymbol.toTypeSymbol(useJavaTime)(localPart)
9192
else ReferenceTypeSymbol(namespace, localPart)
9293
case _ => ReferenceTypeSymbol(namespace, localPart)
9394
}
@@ -147,8 +148,8 @@ case class SchemaDecl(targetNamespace: Option[String],
147148

148149
object SchemaDecl {
149150
def fromXML(node: scala.xml.Node,
150-
context: XsdContext,
151-
config: ParserConfig = new ParserConfig) = {
151+
context: XsdContext,
152+
config: ParserConfig) = {
152153
val schema = (node \\ "schema").headOption.getOrElse {
153154
sys.error("xsd: schema element not found: " + node.toString) }
154155
val targetNamespace = schema.attribute("targetNamespace").headOption map { _.text }
@@ -492,7 +493,7 @@ object SimpleTypeDecl {
492493
def fromXML(node: scala.xml.Node, name: String, family: List[String], config: ParserConfig): SimpleTypeDecl = {
493494
var content: ContentTypeDecl = null
494495
for (child <- node.child) child match {
495-
case <restriction>{ _* }</restriction> => content = SimpTypRestrictionDecl.fromXML(child, family, config)
496+
case <restriction>{ _* }</restriction> => content = SimpTypRestrictionDecl.fromXML(child, family, config)
496497
case <list>{ _* }</list> => content = SimpTypListDecl.fromXML(child, family, config)
497498
case <union>{ _* }</union> => content = SimpTypUnionDecl.fromXML(child, config)
498499
case _ =>

cli/src/main/scala/scalaxb/compiler/xsd/Driver.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ class Driver extends Module { driver =>
7070
}
7171
val includeLocations: Seq[String] = schemaLite.includes map { _.schemaLocation }
7272

73-
def toSchema(context: Context): Schema = {
74-
val schema = SchemaDecl.fromXML(raw, context)
73+
def toSchema(context: Context, config: ParserConfig): Schema = {
74+
val schema = SchemaDecl.fromXML(raw, context, config)
7575
logger.debug("toSchema: " + schema.toString())
7676
schema
7777
}

cli/src/main/scala/scalaxb/compiler/xsd/XsTypeSymbol.scala

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
/*
22
* Copyright (c) 2010 e.e d3si9n
3-
*
3+
*
44
* Permission is hereby granted, free of charge, to any person obtaining a copy
55
* of this software and associated documentation files (the "Software"), to deal
66
* in the Software without restriction, including without limitation the rights
77
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
88
* copies of the Software, and to permit persons to whom the Software is
99
* furnished to do so, subject to the following conditions:
10-
*
10+
*
1111
* The above copyright notice and this permission notice shall be included in
1212
* all copies or substantial portions of the Software.
13-
*
13+
*
1414
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1515
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1616
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -19,15 +19,15 @@
1919
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2020
* THE SOFTWARE.
2121
*/
22-
22+
2323
package scalaxb.compiler.xsd
2424

2525
import javax.xml.namespace.QName
2626

2727
trait XsTypeSymbol extends scala.xml.TypeSymbol {
2828
val name: String
29-
30-
override def toString(): String = name
29+
30+
override def toString(): String = name
3131
}
3232

3333
object XsAnyType extends XsTypeSymbol {
@@ -116,6 +116,7 @@ object XsDuration extends BuiltInSimpleTypeSymbol("javax.xml.datatype.Du
116116
object XsDateTime extends BuiltInSimpleTypeSymbol("javax.xml.datatype.XMLGregorianCalendar") {}
117117
object XsTime extends BuiltInSimpleTypeSymbol("javax.xml.datatype.XMLGregorianCalendar") {}
118118
object XsDate extends BuiltInSimpleTypeSymbol("javax.xml.datatype.XMLGregorianCalendar") {}
119+
object XsJavaLocalDate extends BuiltInSimpleTypeSymbol("java.time.LocalDateTime")
119120
object XsGYearMonth extends BuiltInSimpleTypeSymbol("javax.xml.datatype.XMLGregorianCalendar") {}
120121
object XsGYear extends BuiltInSimpleTypeSymbol("javax.xml.datatype.XMLGregorianCalendar") {}
121122
object XsGMonthDay extends BuiltInSimpleTypeSymbol("javax.xml.datatype.XMLGregorianCalendar") {}
@@ -160,14 +161,15 @@ object XsUnsignedByte extends BuiltInSimpleTypeSymbol("Int") {}
160161
object XsTypeSymbol {
161162
type =>?[A, B] = PartialFunction[A, B]
162163
val LOCAL_ELEMENT = "http://scalaxb.org/local-element"
163-
164-
val toTypeSymbol: String =>? XsTypeSymbol = {
164+
165+
def toTypeSymbol(useJavaTime: Boolean): String =>? XsTypeSymbol = {
165166
case "anyType" => XsAnyType
166167
case "anySimpleType" => XsAnySimpleType
167168
case "duration" => XsDuration
168169
case "dateTime" => XsDateTime
169170
case "time" => XsTime
170-
case "date" => XsDate
171+
case "date" if useJavaTime => XsJavaLocalDate
172+
case "date" if !useJavaTime => XsDate
171173
case "gYearMonth" => XsGYearMonth
172174
case "gYear" => XsGYear
173175
case "gMonthDay" => XsGMonthDay
@@ -207,6 +209,6 @@ object XsTypeSymbol {
207209
case "short" => XsShort
208210
case "unsignedShort" => XsUnsignedShort
209211
case "byte" => XsByte
210-
case "unsignedByte" => XsUnsignedByte
211-
}
212+
case "unsignedByte" => XsUnsignedByte
213+
}
212214
}

sbt-scalaxb/src/main/scala/sbtscalaxb/ScalaxbKeys.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ trait ScalaxbKeys {
4646
lazy val scalaxbSymbolEncodingStrategy = settingKey[SymbolEncodingStrategy.Value]("Specifies the strategy to encode non-identifier characters in generated class names")
4747
lazy val scalaxbEnumNameMaxLength = settingKey[Int]("Truncates names of enum members longer than this value (default: 50)")
4848
lazy val scalaxbUseLists = settingKey[Boolean]("Declare sequences with concrete type List instead of Seq")
49+
lazy val scalaxbUseJavaTime = settingKey[Boolean]("Use Java Time (java.time.*) instead of XMLGregorianCalendar (javax.xml.datatype.*)")
4950

5051
object HttpClientType extends Enumeration {
5152
val None, Dispatch, Gigahorse = Value

sbt-scalaxb/src/main/scala/sbtscalaxb/ScalaxbPlugin.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ object ScalaxbPlugin extends sbt.AutoPlugin {
8989
scalaxbSymbolEncodingStrategy := SymbolEncodingStrategy.Legacy151,
9090
scalaxbEnumNameMaxLength := 50,
9191
scalaxbUseLists := false,
92+
scalaxbUseJavaTime := false,
9293
scalaxbConfig :=
9394
ScConfig(
9495
Vector(PackageNames(scalaxbCombinedPackageNames.value)) ++
@@ -136,7 +137,8 @@ object ScalaxbPlugin extends sbt.AutoPlugin {
136137
(if (scalaxbCapitalizeWords.value) Vector(CapitalizeWords) else Vector()) ++
137138
Vector(SymbolEncoding.withName(scalaxbSymbolEncodingStrategy.value.toString)) ++
138139
Vector(EnumNameMaxLength(scalaxbEnumNameMaxLength.value)) ++
139-
(if (scalaxbUseLists.value) Vector(UseLists) else Vector())
140+
(if (scalaxbUseLists.value) Vector(UseLists) else Vector()) ++
141+
(if (scalaxbUseJavaTime.value) Vector(UseJavaTime) else Vector())
140142
)
141143
))
142144
}

0 commit comments

Comments
 (0)