Monday, November 15, 2010

JAX-RS is really nice for writing REST services. I'm using Jersey 1.3, with Guice 2.0 and jersey-guice to configure things. However, the Jersey JSON provider is horrible. It messes up writing empty and single element arrays, and it writes boolean and numerical values as strings. My first hack around that was to return a JSON string instead of the objects, doing the conversions in-line using Jackson 1.5. That was ugly, so I overwrote META-INF/services/javax.ws.rs.ext.MessageBodyReader and META-INF/services/javax.ws.rs.ext.MessageBodyWriter in the Jersey jar, replacing the Jersey JSON providers with org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider, and it was much better.

I also use the Jersey REST client to talk to Facebook. However, Facebook returns text/javascript;charset=UTF-8 as the content-type, which is not recognized by either the Jersey JSON provider, or the Jackson JAX-RS JSON provider. Again, the first thing I did was to get the content as an InputStream, which I sent to Jackson for object binding. Then, I figured that I could just extend the Jackson JSON provider to accept text/javascript and use that class as the JSON provider.

@Provider
@Consumes({MediaType.APPLICATION_JSON, "text/json", "text/javascript"})
@Produces({MediaType.APPLICATION_JSON, "text/json"})
public class MyJaxbJsonProvider extends JacksonJaxbJsonProvider {
@Override
protected boolean isJsonType(MediaType mediaType) {
if (mediaType != null && "javascript".equals(mediaType.getSubtype()))
return true;
return super.isJsonType(mediaType);
}
}

Now, the code no longer has ugly hacks for JSON. However, any time I get a new Jersey jar, I'll have to overwrite the provider list in the jar, which is ugly. Perhaps I could put my own javax.ws.rs.ext.MessageBodyReader and javax.ws.rs.ext.MessageBodyWriter in a jar, and have it take precedence, but it didn't work the first time I tried it. It might depend on the classpath order of the jars, and having to use the classpath order of jar files to override things is also ugly.

Also on JSON, RFC-4627 says that slashes may be backslash quoted, though the example in section 8 does not backslash quote the slashes. The JSON from Facebook does backslash quote the slashes, but the JSON produced by Jackson does not. I wonder why backslash quoted slashes were explicitly included in the JSON specification. Perhaps it was inherited from Javascript, in which case I wonder why it was that way in Javascript. My only guess is that it had something to do with regular expressions, if it was from Javascript. Otherwise, it just seems weird.

Monday, November 8, 2010

One thing that bugs me about some of the datacenter hosts that I have to access for one reason or another under a generic developer account that has no write access to anything except /tmp is that there is a long delay while xauth tries to lock $HOME/.Xauthority. I've explicitly unset DISPLAY, but that makes no difference.

Monday, November 1, 2010

My initial attempt at making an iframe Facebook app immediately ran into a snag. It seems that if the Safari browser's cookie configuration is "Only from sites I visit", subtitled "Block cookies from third parties and advertisers.", then cookies don't get saved or sent to the iframe. Which means saving the session id in a cookie fails. Having sessions is critical, but I don't know if other browsers have this problem, or whether it's acceptable to fail for users that block iframe cookies (or all cookies). The session id could be stuck in the URL as a matrix parameter with a simple configuration of the servlet container, but it's painful to have to make sure all the URLs that need the session id are rewritten. Plus, the session id would get leaked in Referer headers.

Once I made sure all the URLs had the proper rewriting, it still didn't work, because although Glassfish v3 (74.2) rewrites all the URLs, it never recognizes the sessionid in the URL, and creates a new session. When I switched to Tomcat, it worked with cookies disabled.

Monday, October 25, 2010

Now, I'm working on Facebook apps using OAuth 2.0, and the draft specification says in section 4.2 that JSON is returned when retrieving the access token. However, Facebook's OAuth 2.0 server returns application/x-www-form-urlencoded data. I anticipate things changing without notice, so I'll have to code it flexibly. Of course, it is a draft specification.

As for OAuth 2.0 versus OAuth 1.0, it's a little nicer. Code for computing the signature for OAuth 1.0 is difficult to debug, but, once it's working, it's easy. On the server side, incorrect nonce handling seems like an obvious hole for replay attacks, and OAuth 2.0 is better in that way. Also, unencrypted OAuth 1.0 traffic can still be snooped. Of course, OAuth 2.0 is still subject to traffic analysis. Of course, with Facebook's reputation on privacy, these differences are irrelevant for most Facebook apps, including the ones I'm working on.

Monday, October 18, 2010

After using Guice for a little while, I've started learning how to use it better. I can use @Provides methods to configure objects. I like being able to install() modules for modularity.

For webapps, I can have two web.xml files, one pointing to one configuration, and another pointing to another configuration, such as a test configuration, by specifying the different configuration classes as the listener in web.xml files, where the bindings specify different implementations.

I'm not sure if I like the fluent interface. It's nice for reading the code, but it makes referring to the javadoc more difficult. It also creates a bunch temporary objects, but that isn't really a concern. Guice is supposedly a lot faster than Spring, and the temporary objects probably can be optimized away by escape analysis.

Monday, October 11, 2010

I've only had a cursory look at Google Guice, but this is my first impression as compared with Spring, which I've used a lot more. Using Spring has actually changed the way I approach writing code.

What I like about Guice is that it is statically type-checked. Spring's xml configuration is like a dynamically typed language, and more errors slip through to later stages.

What I like about Spring is that code doesn't need to be written with any Spring-specific calls or constructs, whereas Guice requires Guice-specific annotations. If I only had to deal with code I've written, it wouldn't matter so much. However, Spring makes it hooking in code from external libraries more convenient.

Also, when using Spring, I like being able to specify every last configurable flag in the xml configuration, and anything that truly needs to be tuned can further be extracted into a properties file. Guice seems to make that level of configuration more inconvenient. Perhaps I am overlooking some mechanism, but it seems inconvenient to have to insert yet another annotation to name yet another string field that I want to configure, rather than just being able to inject beans. Guice seems to encourage having a few, high-level, injected objects, rather than every last configurable value injected.

One nice thing about Guice is that it can inject private fields, while Spring requires a public setter method. This is just a minor thing though, since, while the implementing class may have some public setters, the public interface that it is being injected as won't have those public setters. There is also constructor injection, but that is not convenient when there are many parameters to inject.

Monday, October 4, 2010

I ran across a bug in an Android app that I was working on that had me throwing the phone to the floor multiple times in frustration. I finally tracked the problem down to SurfaceHolder.Callback.surfaceChanged() being called twice when the phone is held vertically, but only once when the phone is held sideways. Everyone using the app holds the phone sideways when using the app because the text and icons are all sideways. However, I had said to myself, "Screw that. I'm not going to turn the phone sideways just for that." I don't know what the proper way to fix it is, since I don't know why the code is in SurfaceHolder.Callback.surfaceChanged(), and the person who wrote it had just moved on to another company (Google, actually) a week earlier.