Specifying multiple constructors

820 views
Skip to first unread message

Yaroslav

unread,
Feb 3, 2012, 10:15:54 AM2/3/12
to SnakeYAML
Hi,

What is the proper way to specify multiple constructors for Yaml
object?

For example, what if I want to use both DiceConstructor and
JodaTimeImplicitContructor (taken from standard samples) in the same
document?

Yaroslav

Andrey Somov

unread,
Feb 3, 2012, 10:19:19 AM2/3/12
to snakeya...@googlegroups.com
Hi Yaroslav,
Contructor is statefull, you cannot use more then one. Combine all the specific implementations inside one class.

-
Andrey



Yaroslav

--
You received this message because you are subscribed to the Google Groups "SnakeYAML" group.
To post to this group, send email to snakeya...@googlegroups.com.
To unsubscribe from this group, send email to snakeyaml-cor...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/snakeyaml-core?hl=en.


Yaroslav

unread,
Feb 3, 2012, 10:32:08 AM2/3/12
to snakeya...@googlegroups.com
What I really need is to specify multiple parsers for particular tags. That is I need multiple Constructs not Constructors.

I think it might be usefull to expose something like the following method in Constructor class:

public void setConstruct(tag, construct) {
  this.yamlConstructors.put(tag, construct);
}

Currently yamlConstructors field is protected so I can only add Constructs by subclassing Constructor, which I don't really need to.

Andrey

unread,
Feb 3, 2012, 11:10:48 AM2/3/12
to snakeya...@googlegroups.com

Yaroslav

unread,
Feb 3, 2012, 12:37:18 PM2/3/12
to snakeya...@googlegroups.com
Andrey,

I know how to implement Construct.

In all the samples in order to add custom Constructs to Constructor you override Constructor itself. With the only purpose to access it's protected this.yamlConstructors field. Otherwise this inheritance is not needed.

If Constructor class had the method I described earlier there would be no need in such an override. One could simply write:

Constructor constr=new Constructor();
constr.setConstruct(Tag.TIMESTAMP, new MyTimestampConstruct());
constr.setConstruct(new Tag("!dice"), new ConstructDice());
constr.setConstruct(new Tag("!..."), new My...Construct());
constr.setMultiConstruct(prefix, new PrefixConstruct(prefix, constr));
constr.addTypeDescription(new TypeDescription(MyEntity.class, "!myent"));
...
Yaml yaml=new Yaml(constr);
yaml.addImplicitResolver(new Tag("!dice"), Pattern.compile("\\d+d\\d+"), "123456789");

The whole idea of overriding Constructor just to gain access to its protected field seems artificial.

Moreover all individual Constructs will become independent of one another and could be flexibly added as needed in each particular case. No bundling of Constructs in Constructor subclasses.

I think this would be easier to use and understand.

Yaroslav

--
You received this message because you are subscribed to the Google Groups "SnakeYAML" group.
To view this discussion on the web visit https://groups.google.com/d/msg/snakeyaml-core/-/b6JTd9Vb2nkJ.

Andrey

unread,
Feb 3, 2012, 12:59:14 PM2/3/12
to snakeya...@googlegroups.com
If you feel you know how the API can be improved feel free to send a patch with your proposal. Otherwise, it is not easy to see what you mean.

-
Andrey

Yaroslav

unread,
Feb 3, 2012, 1:21:17 PM2/3/12
to snakeya...@googlegroups.com
Here is the patch. It is very simple. Just add the following two methods to org.yaml.snakeyaml.constructor.BaseConstructor class:

public void setConstruct(Tag tag, Construct construct) {
  yamlConstructors.put(tag, construct);
}

public void setMultiConstruct(String prefix, Construct construct) {
  yamlMultiConstructors.put(prefix, construct);
}



-
Andrey

--
You received this message because you are subscribed to the Google Groups "SnakeYAML" group.
To view this discussion on the web visit https://groups.google.com/d/msg/snakeyaml-core/-/FsJkyJGKqocJ.

Jordan Angold

unread,
Feb 4, 2012, 1:20:07 PM2/4/12
to SnakeYAML
Hi Yaroslav!

I have read through this thread and I think I understand what you are
talking about. I agree completely, and have already proposed a change
that would allow you to specify custom Construct implementations
without ever extending Constructor. The proposal's source code is in:
http://code.google.com/r/jordanangold-separate-config/source/browse ,
but I have not released any artifacts from this branch. Also, since
this proposal has not been accepted, there may be bugs fixed in
mainline SnakeYAML which still exist in my branch.

An example of how to add several custom constructors can be found
here:
http://code.google.com/r/jordanangold-separate-config/source/browse/src/test/java/org/yaml/snakeyaml/constructor/AbstractConstructTest.java

In short, my change separates the SnakeYAML guts (Constructor,
BaseConstructor, SafeConstructor, ...) from the configuration side of
things.

If this is similar to what you were hoping for, perhaps we could get
this integrated into the next release of SnakeYAML. Until then, you
could extend Constructor yourself to provide those two methods. I
agree it is not ideal, but it would be a functional workaround.

Thanks,
/Jordan

Yaroslav

unread,
Feb 4, 2012, 2:52:03 PM2/4/12
to snakeya...@googlegroups.com
Hi Jordan!

Yes, this is similar. My proposal is probably less extensive than yours, but that's the first thing that came to my mind after studying SnakeYAML for one day. The idea of overriding core component without actually overriding any of its methods didn't look right to me.

I have already implemented all necessary workarounds for myself, but I thought this might be useful for other users of SnakeYAML.

Yaroslav

Andrey

unread,
Feb 6, 2012, 3:55:03 AM2/6/12
to snakeya...@googlegroups.com
Yaroslav,
your proposal only covers very simple use cases when the custom implementation of the Construct interface does not need to call the  main statefull Constructor. (Please be aware that the anchors & aliases and recursive objects can only be registered and managed in one central place -  that is why the there is only one main Constructor). Have a look at this example where the custom  implementation of the Construct interface calls 'constructScalar':

If in this example you simply create a scalar yourself, then in case of an anchor the code will not work: how do you get the reference to the already created object ?

1) create your clone
2) massage the code and fix all the tests
3) share with us your ideas


-
Andrey

Yaroslav

unread,
Feb 6, 2012, 4:39:03 AM2/6/12
to snakeya...@googlegroups.com
On Mon, Feb 6, 2012 at 12:55 PM, Andrey <py4...@gmail.com> wrote:
Yaroslav,
your proposal only covers very simple use cases when the custom implementation of the Construct interface does not need to call the  main statefull Constructor. (Please be aware that the anchors & aliases and recursive objects can only be registered and managed in one central place -  that is why the there is only one main Constructor). Have a look at this example where the custom  implementation of the Construct interface calls 'constructScalar':

If in this example you simply create a scalar yourself, then in case of an anchor the code will not work: how do you get the reference to the already created object ?

Perhaps constructScalar() should also be made public, so external classes can call it. And perhaps it should be stressed in documentation that overriding Construct must call constructScalar() (or something else in case of non-scalars) in order to support anchors & aliases.

I agree that my proposal only covers really simple cases, but these could be as well the most frequently used ones. The proposal does not deny original override-constructor method, so that could be used as well for more complex tasks.
 

1) create your clone
2) massage the code and fix all the tests
3) share with us your ideas


I do not think I have that deep understanding of SnakeYAML yet. I can easily miss important things like anchors for example. I just expressed an idea. If you do not see it as being useful or feasible then I do not insist on it at all.
 

-
Andrey

--
You received this message because you are subscribed to the Google Groups "SnakeYAML" group.
To view this discussion on the web visit https://groups.google.com/d/msg/snakeyaml-core/-/7TcAF4w8dSwJ.

Andrey Somov

unread,
Feb 6, 2012, 5:24:22 AM2/6/12
to snakeya...@googlegroups.com

I do not think I have that deep understanding of SnakeYAML yet. I can easily miss important things like anchors for example. I just expressed an idea. If you do not see it as being useful or feasible then I do not insist on it at all.
 
I do not say it is not useful or feasible. I just say that it is _incomplete_. Let me give you an example. Imagine you invented a very fast and efficient algorithm for the String.trim() method.  You simply drop a character if it happens to be a space. If works perfect because you never use tabs. You can say that this code works for majority of cases. But then another user will complain that (even though he calls the API properly) the trailing and leading tabs do not disappear. (Do you think it is enough to say in the documentation that tabs require a special treatment ?) The very same thing may happen with your proposal - it may or may not work depending on the data.

SnakeYAML was developed by a team of developers and over time the code may not have the perfect shape. A fresh critical eye always helps. Give it a try ! The code has 97% coverage. Feel free to change it to see what is failing.
Create your clone and experiment. But please be aware that if you you wish your code to be accepted do not commit too many big changes without communication. The code and its consequences must be understood in order to be accepted.

-
Andrey

Jordan Angold

unread,
Feb 7, 2012, 1:40:40 AM2/7/12
to SnakeYAML
Andrey:

I think what Yaroslav is proposing is the same as I suggested in June.
Except that I followed your line of reasoning too: Construct objects
must have a reference to the Constructor they are working within. In
my implementation, that is provided as an argument to the construct()
method, instead of when inner classes are instantiated.

I have already done the work that you suggest in your most recent
posts. Unless Yaroslav finds it educational, I see no reason to
duplicate effort. I submitted this branch (with substantial
documentation) for review in June:
http://groups.google.com/group/snakeyaml-core/browse_thread/thread/e55d3d78ed4743ef

My branch has at least 97% code coverage and branch coverage.

Yaroslav:

I appreciate you taking the time to post your suggestion here, and
that you took interest in using SnakeYAML. If you have any future
suggestions, please do not hesitate to share. It looks like this
particular suggestion will not be included in SnakeYAML core for some
time, but please don't let that discourage you: if you have more ideas
for features, I would be happy to hear about them and interested in
developing them.

Thanks,
/Jordan

Andrey

unread,
Feb 7, 2012, 3:44:57 AM2/7/12
to snakeya...@googlegroups.com
Jordan,
the change you have proposed:
1) is very big
2) is not backwards-compatible

That is why I would like that someone else reviews your code, gives recommendations and fully supports the change.
(Is it possible to split the change ? Smaller steps are easier to grasp)

Also I think that if we decide to break backwards-compatibility we shall do it in another package to allow users to do a smooth transition. 

I agree that the current API is sometimes heavy and awkward but it is complete and it is already used in many real applications.

May be Yaroslav can spend some time, learn the current API and the Jordan's proposal and together we can decide what and how we change...

It is too late for version 1.10 but this is not the last version ! Who knows may be in a few months YAML 2.0 is going to be finalized and we do not care about backwards-compatibility because it will be broken anyway...

-
Andrey
Reply all
Reply to author
Forward
0 new messages