Closed GoogleCodeExporter closed 9 years ago
Check the tests to see when constructJavaBean2ndStep is used.
If you have a proposal, feel free to change the code and provide a test to see
what you wish to achieve with your proposal.
Original comment by py4fun@gmail.com
on 14 Feb 2013 at 12:13
I'm sorry. I was a bit tired after fighting with snakeyaml. Suspect that my
ticket is not clear enough. Context is:
I use Scala and I have custom serialization and deserialization code. I achieve
my target, but custom deserialization part is a bit junk. I read snakeyaml code
a lot and understand when and how constructJavaBean2ndStep is used.
The problem is that end user (I am) unable to get access to typeDefinitions and
correct constructJavaBean2ndStep for custom case. I am unable to fix
constructJavaBean2ndStep based on typeDefinitions so I re implement
AbstractConstruct. I suspect that it is not so good. It is possible to add
protected Map<Class<? extends Object>, TypeDescription> getTypeDefinitions()?
or
mark
private final Map<Class<? extends Object>, TypeDescription> typeDefinitions;
as protected.
IMHO This is absolutely minor changes. Tests is not needed.
King regards,
Alexey
Original comment by alexey....@gmail.com
on 14 Feb 2013 at 7:35
The fact that only you and only now need such a change might mean that there is
another way to do the same thing.
The test would help to see your use case.
It is not a problem to change the code. We would like just to understand why
the change is required.
Fee free to provide the Scala code.
Original comment by py4fun@gmail.com
on 15 Feb 2013 at 7:42
Here is a code. Please note that TypeSchemaRepresenter at the bottom - only few
lines of code, beautiful. I want to reuse an exists snakeyaml code as much as
possible for the deserialization. Right now I must reimplement
InterfaceConstruct with AbstractConstruct instead of extend ConstructMapping,
sad. TypeSchema.Interface and TypeSchema.Entity are not follow bean naming
conversion for some reasons. I read a documentation and search across an
Internet but not find an any strait solution to recreate custom classes without
bean properties.
object YAML extends Payload.YAMLProcessor[TypeSchema.Interface] {
/** Convert JSON to the object */
def from(data: String): TypeSchema.Interface = {
val yaml = new Yaml(new TypeSchemaConstructor)
yaml.load(data).asInstanceOf[TypeSchema.Interface]
}
/** Convert the object to JSON */
def to(value: TypeSchema.Interface): String = {
val options = new DumperOptions()
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK)
val yaml = new Yaml(new TypeSchemaRepresenter, new DumperOptions())
yaml.dump(value)
}
class TypeSchemaConstructor extends Constructor(classOf[Interface]) {
val interfaceTag = new Tag(classOf[Interface])
val entityTag = new Tag(classOf[Entity])
this.yamlConstructors.put(interfaceTag, new InterfaceConstruct())
this.yamlConstructors.put(entityTag, new EntityConstruct())
def safeConstruct[T: Manifest](tuple: NodeTuple)(implicit owner: String): Option[T] = constructObject(tuple.getValueNode()) match {
case value: T => Option(value)
case unknown => throw new YAMLException("Unexpected %s key '%s' with type %s".
format(owner, constructObject(tuple.getKeyNode), tuple.getValueNode().getTag()))
}
class InterfaceConstruct extends AbstractConstruct {
implicit val owner = "TypeSchema.Interface"
def construct(node: Node): AnyRef = node match {
case node: MappingNode =>
var id: Option[String] = None
var name: Option[String] = None
var description: Option[String] = None
var entities: scala.collection.mutable.Buffer[TypeSchema.Entity] = new scala.collection.mutable.ArrayBuffer
for (value <- node.getValue())
constructObject(value.getKeyNode()) match {
case "id" => id = safeConstruct[String](value)
case "name" => name = safeConstruct[String](value)
case "description" => description = safeConstruct[String](value)
case "entities" =>
val node = value.getValueNode() match {
case seq: SequenceNode =>
entities = for (value <- seq.getValue()) yield {
value.setTag(entityTag)
constructObject(value).asInstanceOf[TypeSchema.Entity]
}
case unknown => throw new YAMLException("Unexpected TypeSchema.Interface 'entities' type " + unknown.getClass())
}
case other => log.warn(s"unknown TypeSchema.Interface key: $other")
}
val schema = for {
id <- id
name <- name
description <- description
} yield new TypeSchema(UUID.fromString(id), name, description, immutable.HashSet(entities.filter(_ != null): _*))
schema getOrElse {
log.error(s"Unable to load TypeSchema.Interface id:$id, name:$name, description:$description, entities:" + entities.mkString)
null
}
case unknown =>
throw new YAMLException("Unexpected TypeSchema.Interface node type " + unknown.getTag())
}
}
class EntityConstruct extends AbstractConstruct {
implicit val owner = "TypeSchema.Entity"
def construct(node: Node): AnyRef = node match {
case node: MappingNode =>
var `type`: Option[String] = None
var alias: Option[String] = None
var availability: Option[Boolean] = None
var description: Option[String] = None
for (value <- node.getValue())
constructObject(value.getKeyNode()) match {
case "type" => `type` = safeConstruct[String](value)
case "alias" => alias = safeConstruct[String](value)
case "availability" => availability = safeConstruct[java.lang.Boolean](value).map(Boolean.box(_))
case "description" => description = safeConstruct[String](value)
case other => log.warn(s"unknown TypeSchema.Entity key: $other")
}
val entity = for {
`type` <- `type`
alias <- alias
availability <- availability
description <- description
} yield TypeSchema.Entity(Symbol(`type`), alias, availability, description)
entity.getOrElse {
log.error(s"Unable to load TypeSchema.Entity type:%s, alias:$alias, availability:$availability, description:$description".format(`type`))
null
}
case unknown =>
throw new YAMLException("Unexpected TypeSchema.Entity node type " + unknown.getTag())
}
}
}
class TypeSchemaRepresenter extends Representer {
multiRepresenters.put(classOf[Interface], new InterfaceRepresent)
multiRepresenters.put(classOf[Entity], new EntityRepresent)
class InterfaceRepresent extends Represent {
override def representData(data: AnyRef): Node = {
val schema = data.asInstanceOf[TypeSchema]
val map = new java.util.HashMap[String, AnyRef]()
map.put("id", schema.id.toString())
map.put("name", schema.name)
map.put("description", schema.description)
map.put("entities", seqAsJavaList(schema.entities.toSeq))
representMapping(Tag.MAP, map, null)
}
}
class EntityRepresent extends Represent {
override def representData(data: AnyRef): Node = {
val entity = data.asInstanceOf[Entity]
val map = new java.util.HashMap[String, AnyRef]()
map.put("type", entity.typeSymbol.name)
map.put("alias", entity.alias)
map.put("availability", Boolean.box(entity.availability))
map.put("description", entity.description)
representMapping(Tag.MAP, map, null)
}
}
}
}
}
Example of serialized data:
id: ec2cba2f-68b9-47fb-8616-f8d0cc926ed6
description: blablabla
name: lalala
entities:
- {alias: '*thereIsNoData_text', description: tadadada, type: String,
availability: true}
Original comment by alexey....@gmail.com
on 15 Feb 2013 at 9:00
are you working with some open source project? Where I could look in
TypeSchema.Interface ?
-alex
Original comment by alexande...@gmail.com
on 18 Feb 2013 at 6:55
Project will be open source. Right now it is unpublished.
Please note: "TypeSchema.Interface and TypeSchema.Entity are not follow bean
naming conversion for some reasons." I don't want to add @beanproperty
annotation to trait or flood it with getters and setters.
Could you please explain, how concrete realization could help for this case.
The problem is: end user unable to reuse library code for deserialize custom
nested classes. And there is neither a documentation nor examples of such type
deserialization. Rewriting library code with copy'n'paste or designing
workaround instead just extend exists class a bit inappropriate. Please correct
me.
/**
* The type schema entity. It is a tuple typeSymbol -> context information
*/
case class Entity(
/** typeSymbol */
val typeSymbol: Symbol,
/** typeSymbol alias */
val alias: String,
/** Availability flag for user (some types may exists, but not involved in new element template creation) */
val availability: Boolean,
/** The enumeration description */
val description: String) {
lazy val view: String = if (alias.startsWith("*"))
Resources.messages.get(alias.substring(1)).getOrElse {
val result = alias.substring(1)
val trimmed = if (result.endsWith("_text"))
result.substring(0, result.length - 5)
else
result
trimmed(0).toString.toUpperCase + trimmed.substring(1)
}
else if (alias.isEmpty())
Resources.messages.get(typeSymbol.name.toLowerCase() + "_text").getOrElse(typeSymbol.name)
else
alias
}
/**
* The base TypeSchema interface
*/
trait Interface {
/** The type schema id */
val id: UUID
/** The type schema name */
val name: String
/** The type schema description */
val description: String
/** Type schema entities */
val entities: immutable.HashSet[Entity]
/** The copy constructor */
def copy(id: UUID = this.id,
name: String = this.name,
description: String = this.description,
entities: immutable.HashSet[TypeSchema.Entity] = this.entities): this.type
}
Original comment by alexey....@gmail.com
on 18 Feb 2013 at 7:36
I am just curious :)
Reason I'd like to see "bean" is that in my clone I've tried (hopefully I will
continue) to make "bean" (de)serialization easier by using customized
TypeDescriptions.
We will make typeDefinitions protected.
Original comment by alexande...@gmail.com
on 18 Feb 2013 at 8:33
Done. Please try the latest 1.12-SNAPSHOT
http://code.google.com/p/snakeyaml/source/detail?r=31466f3a58a266f49fc13e01375d6
2263aefaf3b
Original comment by py4fun@gmail.com
on 18 Feb 2013 at 5:53
Original comment by py4fun@gmail.com
on 2 Apr 2013 at 5:01
Original issue reported on code.google.com by
alexey....@gmail.com
on 13 Feb 2013 at 3:20