Friday, July 26, 2013

Custom Deserializer in Jackson and validation

tl;dr: it is important to add input validation to custom json deserializers in Jackson.

In RHQ we make use of Json parsing in a few places - be it directly in the as7/Wildfly plugin, be it in the REST-api indirectly via RESTEasy 2.3.5, that already does the heavy lifting.

Now we have a bean Link that looks like

public class Link {
String rel;
String href;
}

The standard way for serializing this is

{ "rel":"edit", "href":"http://acme.org" }

As we need a different format I have written a custom serializer and attached it on the class.

@JsonSerialize(using = LinkSerializer.class)
@JsonDeserialize(using = LinkDeserializer.class)
@Produces({"application/json","application/xml"})
public class Link {

private String rel;
private String href;

This custom format looks like:

{
"edit": {
"href": "http://acme.org"
}
}

As a client can also send links, some custom deserialization needs to happen. A first cut of the deserializer looked like this and worked well:

public class LinkDeserializer extends JsonDeserializer<Link>{

@Override
public Link deserialize(JsonParser jp,
DeserializationContext ctxt) throws IOException
{
String tmp = jp.getText(); // {
jp.nextToken(); // skip over { to the rel
String rel = jp.getText();
jp.nextToken(); // skip over {
[…]

Link link = new Link(rel,href);

return link;
}

Now what happened the other day was that in some tests I was sending data and our server blew up horribly. Memory usage grew, the garbage collector took huge amounts of cpu time and the call eventually terminated with an OutOfMemoryException.

After some investigation I found that the client did not send the Link object in our special format, but in the original format that I showed first. Further investigation showed that in fact the LinkDeserializer was consuming the tokens from the stream as seen above and then also swallowing subsequent tokens from the input. So when it returned, the whole parser was in a bad shape and was then trying to copy large arrays around until we saw the OOME.

After I got this, I changed the implementation to add validation and to bail out early on invalid input, so that the parser won’t get into bad shape on invalid input:

    public Link deserialize(JsonParser jp,
DeserializationContext ctxt) throws IOException
{

String tmp = jp.getText(); // {
validate(jp, tmp,"{");
jp.nextToken(); // skip over { to the rel
String rel = jp.getText();
validateText(jp, rel);
jp.nextToken(); // skip over {
tmp = jp.getText();
validate(jp, tmp,"{");
[…]

Those validate*() then simply compare the token with the passed expected value and throw an Exception on unexpected input:

    private void validate(JsonParser jsonParser, String input,
String expected) throws JsonProcessingException {
if (!input.equals(expected)) {
throw new JsonParseException("Unexpected token: " + input,
jsonParser.getTokenLocation());
}
}

The validation can perhaps be improved more, but you get the idea.




Monday, July 15, 2013

JavaFX UI for the RHQ plugin generator (updated)

In RHQ we have a tool to generate initial plugin skeletons, the plugin generator. This is a standalone tool, that you can use to get going with plugin development.
This is for example described in the "How to write a plugin" article.

Now my colleague Simeon always wanted a graphical frontend (he is very much in favor of graphical frontends, while I am one of those old Unix-neckbeards :). Inspired from this years Java Forum Stuttgart I sat down on the weekend and played a bit with JavaFX. The result is a first cut of UI frontend for the generator:

UI for the plugin generator

On top you see a message bar, that shows field validation issues, the middle is the part where you enter the settings and at the bottom you get a short description for each property.

I've pushed a first cut, that is not yet complete, but you will get the idea. Help is always appreciated.
Code is in RHQ git under modules/helpers/pluginGen.

[update]

I continued working a bit on the generator and have added a possibility to give a directory that contains classes that have been annotated with the annotations from the org.rhq.helpers:rhq-pluginAnnotations module.

Screenshot scan-for-annotations

A class could look like this


public class FooBean {

@Metric(description = "How often was this bean invoked",
displayType = DisplayType.SUMMARY,
measurementType = MeasurementType.DYNAMIC,
units = Units.SECONDS)
int invocationCount;

@Metric(description = "Just a foo", dataType = DataType.TRAIT)
String lastCommand;

@Operation(description = "Increase the invocation count")
public int increaseCounter() {
invocationCount++;
return invocationCount;
}

@Operation(description = "Decrease the counter")
public void decreaseCounter(@Parameter(description
= "How much to decrease?", name = "by") int by) {
invocationCount -= by;
}

And the generator would then create the respective <metric> and <operation> elements in the plugin descriptor - in this case you don't need to select the two "Has Metrics/Operations" flags above.

Now this work is still not finished. And in fact it would be good to find a common set of annotations for a more broader scope of projects.

Wednesday, July 03, 2013

Using Asciidoc with MarsEdit - first cut

With Asciidoc becoming more popular due to Asciidoctor I started authoring documents in Asciidoc and thought it would be a good idea to use that for my blogging as well (in the long run I may set up my blog in Awestruct, but for now Blogger has to do.

Usually I am using
MarsEdit to write my posts, as it is just convenient for me. MarsEdit now allows to write custom text filters since the recently released version 3.6. There are a few such filters provided like for Markdown or Textile, so that you can write blog posts inside MarsEdit in those markup languages and still be able to post to e.g. Blogger, which requires html.

When I saw the filters announced, I thought, that should be possible with Asciidoc as well.

So basically to achieve this, you need to create a directory

~/Library/Application Support/MarsEdit/TextFilters/Asciidoc_0.0.1

and then create a file Asciidoc.rb with the following content:

#!/usr/bin/ruby

require 'rubygems'
require 'asciidoctor'

input = $stdin.read

puts Asciidoctor.render(input)

Make that file executable and install the AsciiDoctor gem.

Then (re-start) MarsEdit and select Asciidoc as Preview Text filter in the connection settings of the blogger account ( see Mars Edit per Blog Settings ). Then click on the "Posting" tab and click on "Apply preview filter before posting".

Unfortunately I have not yet found out how to include (remote) images

NOTE

Not all AsciiDoc markups make sense, as AsciiDoctor usually uses some CSS, that may not be present on the target blog system. It may be not too hard though to create a special "blogger" backend, that uses
blogger css for that or to tell blogger to accept the AsciiDoctor css files

This screenshot shows MarsEdit with source and preview.

I hope this little post makes sense and encourages people to experiment with it in order to make AsciiDoc a real alternative to