diff --git a/cli/src/main/scala/scalaxb/compiler/xsd2/ContextProcessor.scala b/cli/src/main/scala/scalaxb/compiler/xsd2/ContextProcessor.scala index 08c7840e5..f267038f1 100644 --- a/cli/src/main/scala/scalaxb/compiler/xsd2/ContextProcessor.scala +++ b/cli/src/main/scala/scalaxb/compiler/xsd2/ContextProcessor.scala @@ -17,7 +17,7 @@ trait ContextProcessor extends ScalaNames { self: Namer with Lookup => tagged.tag.toString + "??" } - def getTraitName(tagged: Tagged[XComplexType]): String = + def getTraitName(tagged: TaggedType[XComplexType]): String = context.traitNames.get(tagged) getOrElse { error(tagged.tag.toString + "??") } diff --git a/cli/src/main/scala/scalaxb/compiler/xsd2/Generator.scala b/cli/src/main/scala/scalaxb/compiler/xsd2/Generator.scala index 0bd75c6e2..0c8de2926 100644 --- a/cli/src/main/scala/scalaxb/compiler/xsd2/Generator.scala +++ b/cli/src/main/scala/scalaxb/compiler/xsd2/Generator.scala @@ -48,7 +48,7 @@ class Generator(val schema: ReferenceSchema, case _ => Vector() }): _*) - def processComplexType(decl: Tagged[XComplexType]): Seq[Trippet] = + def processComplexType(decl: TaggedType[XComplexType]): Seq[Trippet] = if (context.baseToSubs.contains(decl)) { generateBaseComplexTypeTrait(buildTraitSymbol(decl), decl) +: (if (decl.abstractValue) Vector() @@ -58,7 +58,7 @@ class Generator(val schema: ReferenceSchema, /** recursively return compositors. */ - private def compositorsR(decl: Tagged[XComplexType]): Seq[TaggedParticle[KeyedGroup]] = { + private def compositorsR(decl: TaggedType[XComplexType]): Seq[TaggedParticle[KeyedGroup]] = { val ps = decl.primarySequence val singleps = ps map { tagged => Occurrence(tagged).isSingle } getOrElse {false} @@ -82,7 +82,7 @@ class Generator(val schema: ReferenceSchema, else ps.toSeq ++ nonps } - def generateComplexTypeEntity(sym: ClassSymbol, decl: Tagged[XComplexType]): Trippet = { + def generateComplexTypeEntity(sym: ClassSymbol, decl: TaggedType[XComplexType]): Trippet = { logger.debug("generateComplexTypeEntity: emitting %s" format sym.toString) lazy val attributeSeqRef: Tagged[AttributeSeqParam] = TaggedAttributeSeqParam(AttributeSeqParam(), decl.tag) @@ -132,7 +132,7 @@ class Generator(val schema: ReferenceSchema, compositorCodes: _*) } - private def generateDefaultFormat(sym: ClassSymbol, decl: Tagged[XComplexType], + private def generateDefaultFormat(sym: ClassSymbol, decl: TaggedType[XComplexType], hasAttributes: Boolean, hasSequenceParam: Boolean, longAll: Boolean): Tree = { val particles = decl.splitNonEmptyParticles val unmixedParserList = particles map { buildParticleParser(_, decl.effectiveMixed, decl.effectiveMixed) } @@ -242,7 +242,7 @@ class Generator(val schema: ReferenceSchema, ).flatten) } - private def generateBaseComplexTypeTrait(sym: ClassSymbol, decl: Tagged[XComplexType]): Trippet = { + private def generateBaseComplexTypeTrait(sym: ClassSymbol, decl: TaggedType[XComplexType]): Trippet = { logger.debug("generateBaseComplexTypeTrait: emitting %s" format sym.toString) lazy val attributeSeqRef: Tagged[AttributeSeqParam] = TaggedAttributeSeqParam(AttributeSeqParam(), decl.tag) @@ -270,7 +270,7 @@ class Generator(val schema: ReferenceSchema, makeImplicitValue(sym)) } - private def generateBaseComplexTypeFormat(sym: ClassSymbol, decl: Tagged[XComplexType]): Tree = { + private def generateBaseComplexTypeFormat(sym: ClassSymbol, decl: TaggedType[XComplexType]): Tree = { logger.debug("generateBaseComplexTypeFormat - ", sym) val dfmt = defaultFormatterSymbol(sym) @@ -323,7 +323,7 @@ class Generator(val schema: ReferenceSchema, NEW(ANONDEF(dfmt.decodedName) := BLOCK()) } - def complexTypeSuperTypes(decl: Tagged[XComplexType]): Seq[Type] = { + def complexTypeSuperTypes(decl: TaggedType[XComplexType]): Seq[Type] = { def choices: List[TaggedKeyedGroup] = (for { sch <- context.schemas @@ -409,23 +409,29 @@ class Generator(val schema: ReferenceSchema, Trippet(TRAITDEF(sym)) } - def processSimpleType(decl: Tagged[XSimpleType]): Seq[Trippet] = + def processSimpleType(decl: TaggedType[XSimpleType]): Seq[Trippet] = Seq(generateSimpleType(userDefinedClassSymbol(decl), decl)) - private def generateSimpleType(sym: ClassSymbol, decl: Tagged[XSimpleType]) = { + private def generateSimpleType(sym: ClassSymbol, decl: TaggedType[XSimpleType]) = { val enums = filterEnumeration(decl) val enumValues = enums map { enum => CASEOBJECTDEF(userDefinedClassSymbol(enum)) withParents(sym) := BLOCK( - DEF(Any_toString) withFlags(Flags.OVERRIDE) := LIT(enum.value.value) + DEF(Any_toString) withFlags(Flags.OVERRIDE) := LIT(decl.enumValue(enum).toString) ) } + val valueTree: Tree = + if (decl.qnameBased) PAREN(BLOCK( + VAL(TUPLE(ID("ns"), ID("localPart"))) := (HelperClass DOT "splitQName") APPLY(REF("value"), REF("scope")), + NEW(QNameClass, REF("ns") DOT "orNull", REF("localPart")) TOSTRING + )) + else REF("value") val companionTree: Tree = if (enums.isEmpty) OBJECTDEF(sym) := BLOCK( - DEF("fromString", sym) withParams(PARAM("value", StringClass)) := REF(sym) APPLY() + DEF("fromString", sym) withParams(PARAM("value", StringClass), PARAM("scope", NamespaceBindingClass)) := REF(sym) APPLY() ) else OBJECTDEF(sym) := BLOCK( - DEF("fromString", sym) withParams(PARAM("value", StringClass)) := REF("value") MATCH( - enums map { enum => CASE (LIT(enum.value.value)) ==> REF(userDefinedClassSymbol(enum)) } + DEF("fromString", sym) withParams(PARAM("value", StringClass), PARAM("scope", NamespaceBindingClass)) := valueTree MATCH( + enums map { enum => CASE (LIT(decl.enumValue(enum).toString)) ==> REF(userDefinedClassSymbol(enum)) } )) Trippet(TRAITDEF(sym).tree :: companionTree :: enumValues.toList, Nil, @@ -433,13 +439,15 @@ class Generator(val schema: ReferenceSchema, makeImplicitValue(sym) :: Nil) } - private def generateSimpleTypeFormat(sym: ClassSymbol, decl: Tagged[XSimpleType]): Tree = { + private def generateSimpleTypeFormat(sym: ClassSymbol, decl: TaggedType[XSimpleType]): Tree = { val dfmt = defaultFormatterSymbol(sym) TRAITDEF(dfmt.decodedName) withParents(XMLFormatClass TYPE_OF sym) := BLOCK(List( DEF("reads", eitherType(StringClass, sym)) withParams( - PARAM("seq", NodeSeqClass), PARAM("stack", TYPE_LIST(ElemNameClass))) := - RIGHT((sym DOT "fromString")(REF("seq") DOT "text")), + PARAM("seq", NodeSeqClass), PARAM("stack", TYPE_LIST(ElemNameClass))) := REF("seq") MATCH( + CASE(ID("elem") withType(ElemClass)) ==> RIGHT((sym DOT "fromString")(REF("elem") DOT "text", REF("elem") DOT "scope")), + CASE(WILDCARD) ==> RIGHT((sym DOT "fromString")(REF("seq") DOT "text", REF(TopScopeModule))) + ), DEF("writes", NodeSeqClass) withParams(PARAM("__obj", sym), PARAM("__namespace", optionType(StringClass)), PARAM("__elementLabel", optionType(StringClass)), diff --git a/cli/src/main/scala/scalaxb/compiler/xsd2/Lookup.scala b/cli/src/main/scala/scalaxb/compiler/xsd2/Lookup.scala index 7f29c0d2a..4622c9914 100644 --- a/cli/src/main/scala/scalaxb/compiler/xsd2/Lookup.scala +++ b/cli/src/main/scala/scalaxb/compiler/xsd2/Lookup.scala @@ -114,10 +114,10 @@ trait Lookup extends ContextProcessor { self: Namer with Splitter with Symbols = tagged.value.ref map { ref => buildAttributeGroupTypeSymbol(resolveAttributeGroup(ref)) } getOrElse { userDefinedClassSymbol(tagged) } - def buildComplexTypeSymbol(tagged: Tagged[XComplexType]): ClassSymbol = + def buildComplexTypeSymbol(tagged: TaggedType[XComplexType]): ClassSymbol = userDefinedClassSymbol(tagged.tag.namespace, getName(tagged)) - def buildTraitSymbol(tagged: Tagged[XComplexType]): ClassSymbol = + def buildTraitSymbol(tagged: TaggedType[XComplexType]): ClassSymbol = userDefinedClassSymbol(tagged.tag.namespace, getTraitName(tagged)) def buildNamedGroupSymbol(tagged: Tagged[XNamedGroup]): ClassSymbol = diff --git a/cli/src/main/scala/scalaxb/compiler/xsd2/SchemaContext.scala b/cli/src/main/scala/scalaxb/compiler/xsd2/SchemaContext.scala index 73dfb72c6..829717e5a 100644 --- a/cli/src/main/scala/scalaxb/compiler/xsd2/SchemaContext.scala +++ b/cli/src/main/scala/scalaxb/compiler/xsd2/SchemaContext.scala @@ -28,7 +28,7 @@ import java.net.URI case class SchemaContext(schemas: mutable.ListBuffer[ReferenceSchema] = mutable.ListBuffer(), names: mutable.ListMap[Tagged[_], String] = mutable.ListMap(), - traitNames: mutable.ListMap[Tagged[XComplexType], String] = mutable.ListMap(), + traitNames: mutable.ListMap[TaggedType[XComplexType], String] = mutable.ListMap(), packageNames: mutable.ListMap[Option[String], Option[String]] = mutable.ListMap(), - baseToSubs: mutable.ListMap[Tagged[XComplexType], List[Tagged[XComplexType]]] = mutable.ListMap(), + baseToSubs: mutable.ListMap[TaggedType[XComplexType], List[TaggedType[XComplexType]]] = mutable.ListMap(), prefixes: mutable.ListMap[URI, String] = mutable.ListMap()) diff --git a/cli/src/main/scala/scalaxb/compiler/xsd2/SchemaOps.scala b/cli/src/main/scala/scalaxb/compiler/xsd2/SchemaOps.scala index 734614510..828308ae7 100644 --- a/cli/src/main/scala/scalaxb/compiler/xsd2/SchemaOps.scala +++ b/cli/src/main/scala/scalaxb/compiler/xsd2/SchemaOps.scala @@ -180,6 +180,31 @@ case class SimpleTypeOps(decl: TaggedType[XSimpleType]) { case _ => sys.error("baseType#: Unsupported content " + decl.xSimpleDerivationOption3.value.toString) } } + /** this decl is a decendant of QName. */ + def qnameBased(implicit lookup: Lookup): Boolean = { + import Defs._ + import lookup.{BuiltInType, SimpleType} + import scalaxb.compiler.xsd.XsQName + decl.value.xSimpleDerivationOption3.value match { + case XRestriction(_, _, _, Some(base), _) => + QualifiedName(base) match { + case BuiltInType(TaggedSymbol(XsQName, _)) => true + case SimpleType(tagged) => SimpleTypeOps(tagged).qnameBased + case _ => false + } + case XRestriction(_, XSimpleRestrictionModelSequence(Some(simpleType), _), _, _, _) => + SimpleTypeOps(Tagged(simpleType, decl.tag)).qnameBased + case _ => false + } + } + + def enumValue(enum: Tagged[XNoFixedFacet])(implicit lookup: Lookup): Any = + if (qnameBased) { + import scalaxb.compiler.Module.splitTypeName + val (ns, localPart) = splitTypeName(enum.value.value, lookup.scopeEv) + QualifiedName(ns map {new URI(_)}, localPart) + } + else enum.value.value } /** represents attributes param */ diff --git a/cli/src/main/scala/scalaxb/compiler/xsd2/namer.scala b/cli/src/main/scala/scalaxb/compiler/xsd2/namer.scala index 229b77ddc..ea9d2510f 100644 --- a/cli/src/main/scala/scalaxb/compiler/xsd2/namer.scala +++ b/cli/src/main/scala/scalaxb/compiler/xsd2/namer.scala @@ -45,7 +45,7 @@ trait Namer extends ScalaNames { self: Lookup with Splitter => }} } - def nameSimpleTypes(decl: Tagged[XSimpleType]) { + def nameSimpleTypes(decl: TaggedType[XSimpleType]) { if (containsEnumeration(decl)) { val name = makeProtectedSimpleTypeName(decl) logger.debug("nameSimpleTypes: named %s", name) @@ -54,7 +54,7 @@ trait Namer extends ScalaNames { self: Lookup with Splitter => } } - def nameTrait(decl: Tagged[XComplexType]) { + def nameTrait(decl: TaggedType[XComplexType]) { val rawName = decl.name.get val initialName = if (rawName.last == 'e') rawName.dropRight(1) + "able" else rawName + "able" @@ -63,7 +63,7 @@ trait Namer extends ScalaNames { self: Lookup with Splitter => traitNames(decl) = name } - def nameComplexTypes(decl: Tagged[XComplexType]) { + def nameComplexTypes(decl: TaggedType[XComplexType]) { val name = makeProtectedComplexTypeName(decl) logger.debug("nameComplexTypes: named %s", name) names(decl) = name @@ -83,7 +83,7 @@ trait Namer extends ScalaNames { self: Lookup with Splitter => } } - def nameComplexTypeCompositors(decl: Tagged[XComplexType]) { + def nameComplexTypeCompositors(decl: TaggedType[XComplexType]) { val primarySequence = decl.primarySequence implicit val s = schema.unbound val cs: Seq[TaggedParticle[KeyedGroup]] = decl.toSeq collect { @@ -127,9 +127,9 @@ trait Namer extends ScalaNames { self: Lookup with Splitter => } } - def nameEnumValues(decl: Tagged[XSimpleType]) { + def nameEnumValues(decl: TaggedType[XSimpleType]) { filterEnumeration(decl) map { enum => - names(enum) = makeProtectedEnumTypeName(enum) + names(enum) = makeProtectedEnumTypeName(enum, decl) } } @@ -140,14 +140,14 @@ trait Namer extends ScalaNames { self: Lookup with Splitter => def makeProtectedElementTypeName(elem: Tagged[XElement]): String = makeProtectedTypeName(elem.name, "", elem.tag, true) - def makeProtectedComplexTypeName(decl: Tagged[XComplexType]): String = + def makeProtectedComplexTypeName(decl: TaggedType[XComplexType]): String = makeProtectedTypeName(decl.name, "Type", decl.tag, true) - def makeProtectedSimpleTypeName(decl: Tagged[XSimpleType]): String = + def makeProtectedSimpleTypeName(decl: TaggedType[XSimpleType]): String = makeProtectedTypeName(decl.name, "Type", decl.tag, true) - def makeProtectedEnumTypeName(enum: Tagged[XNoFixedFacet]): String = - makeProtectedTypeName(enum.value.value, "Value", enum.tag, true) + def makeProtectedEnumTypeName(enum: Tagged[XNoFixedFacet], decl: TaggedType[XSimpleType]): String = + makeProtectedTypeName(decl.enumValue(enum).toString, "Value", enum.tag, true) def makeProtectedNamedGroup(tagged: Tagged[XNamedGroup]): String = makeProtectedTypeName(tagged.name.get + "Group", "", tagged.tag, true) diff --git a/cli/src/main/scala/scalaxb/compiler/xsd2/symbols.scala b/cli/src/main/scala/scalaxb/compiler/xsd2/symbols.scala index e92844082..3eeded661 100644 --- a/cli/src/main/scala/scalaxb/compiler/xsd2/symbols.scala +++ b/cli/src/main/scala/scalaxb/compiler/xsd2/symbols.scala @@ -34,9 +34,6 @@ trait Symbols { lazy val JavaxXmlNamespacePackage = JavaxXmlPackageClass.newPackage("namespace") lazy val JavaxXmlNamespacePackageClass = JavaxXmlNamespacePackage.moduleClass lazy val QNameClass = JavaxXmlNamespacePackageClass.newClass("QName") - - // workaround treehugger 0.2.0 bug - lazy val NamespaceBindingClass = definitions.getClass("scala.xml.NamespaceBinding") def xmlFormatType(arg: Type): Type = appliedType(XMLFormatClass.typeConstructor, List(arg)) def parserType(arg: Type): Type = appliedType(ParserClass.typeConstructor, List(arg)) diff --git a/cli/src/test/scala/EntitySpec.scala b/cli/src/test/scala/EntitySpec.scala index ba5965044..202b3b8b3 100644 --- a/cli/src/test/scala/EntitySpec.scala +++ b/cli/src/test/scala/EntitySpec.scala @@ -17,6 +17,7 @@ object EntitySpec extends Specification { def is = sequential ^ "each enumerations represented as case object" ! enum2^ "be referenced as the trait" ! enum3^ "generate a companion object named similarly" ! enum4^ + "generate a fromString method using underlying value if it derives from QName" !enum5^ end^ "top-level complex types should" ^ "generate a case class named similarly" ! complexType1^ @@ -85,6 +86,11 @@ object EntitySpec extends Specification { def is = sequential ^ + + + + + @@ -109,6 +115,18 @@ object EntitySpec extends Specification { def is = sequential ^ enumEntitySource must contain("""object MilkType {""") } + def enum5 = { + enumEntitySource must contain("""object QNameEnum { + def fromString(value: String, scope: scala.xml.NamespaceBinding): example.QNameEnum = + ({ + val (ns, localPart) = scalaxb.Helper.splitQName(value, scope) + new javax.xml.namespace.QName(ns.orNull, localPart).toString + }) match { + case "{http://www.example.com/}Receiver" => example.U123httpu58u47u47wwwu46exampleu46comu47u125Receiver + } +}""") + } + lazy val complexTypeEntitySource = module.processNode(complexTypeCardinalityXML, "example")(0) lazy val expectedComplexTypeTest =