Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

Thursday, November 29, 2007

JSR-311 at USP

I gave a talk about RESTful Web Services and JSR-311 at our local USPJUG meeting, the slides are available here (in portuguese).

Wednesday, November 14, 2007

Event "Conexão Java 2007"

This past week I've attended an event called Conexão Java. I've posted my notes on the other blog.

Sunday, December 03, 2006

More Stupid Tiger Tricks

I'm trying to collect some idioms for programming with Java 5 generics, with varying degrees of usefulness, that I found scattered on different places. [Edit]Hopefully I fixed the whitespace problems on the code snippets. Blogger is pretty weak for working with source code, but now I believe its alright. As a bonus, I threw in another item on the end. I guess I'm all out of generic idioms for now.[/Edit]

Union Types


Let's say I have a method to remotely execute some task. Its signature could be something like this:

public void compute(Runnable task)

But there is a catch, we would also like the argument to be Serializable. We could define an application specific interface like

interface Task extends Runnable, Serializable {}

but that would prevent us from accepting exiting classes that just happened to implement both of these interfaces. Java 5 allows us to specify exactly that with union type bounds for type arguments. It is actually pretty easy, see how we apply the technique to our example:

public <T extends Runnable & Serializable> void compute(T task)

I advice you to reserve this idiom mostly for interacting with third-party code. If you find the need to require union types frequently on your own code, there is probably something wrong with the design and some refactoring may be in order.

Casting with a type token


"Know and use the libraries" is one of the most important items in Josh Bloch's Effective Java book. It's also one I frequently violate, only to regret later on. For instance, had I read class Class' documentation attentively, I could have avoided many unchecked cast warnings. An example is in order:

class Registry {
public void storeObject(Object obj) { }
public T getObject(Class<T> ofClass) {}
}

I think this class is pretty self explanatory, it can store an object indexed by it's class and later retrieve the stored instance. The challenge is how to implement it without upsetting the compiler. (And yes, @SupressWarnings("unchecked") is cheating...). For those of you who have done your homework and read class Class' javadocs you know this isn't much of a challenge after all, see:
   
class Registry {
private Map<Class<?>, Object> objects = new HashMap<Class<?>, Object>();

public void storeObject(Object obj) {
objects.put(obj.getClass(), obj);
}

public <T> T getObject(Class<T> ofClass) {
Object instance = objects.get(ofClass);
return ofClass.cast(instance);
}
}

Safe dynamic class loading


More goodies from Class class. Let's see how to dynamically load using generics. Again, we start with an example:

public interface ServiceLocator {
public Executor getExecutor();
}

This is a simple service locator that knows how to get an Executor instance. Service locators usually find service instances from naming services (in a Java EE environment, JNDI is most likely). But a simpler implementation could just read concrete class names from a properties file and instantiate the objects on construction. Let's take a shot at coding this up:

class ServiceLocatorProps implements ServiceLocator {
private Executor executor;

public ServiceLocatorProps() throws Exception {
Properties props = new Properties();
props.load(getClass().getResourceAsStream("services.properties"));

String executorClassName = props.getProperty(
"java.util.concurrent.Executor");

Class<Executor> executorClass =
(Class<Executor>) Class.forName(executorClassName);
//WARNING!!
this.executor = executorClass.newInstance();
}

public Executor getExecutor() {
return executor;
}

}


Please don't pay attention to the inexistent Exception handling. The point here is that the call to Class.forName() is followed by an unckecked cast and the compiler will promply warn us all about it. The correct code for this constructor would be:

public ServiceLocatorProps() throws Exception {
Properties props = new Properties();
props.load(getClass().getResourceAsStream("services.properties"));

String executorClassName = props.getProperty(
"java.util.concurrent.Executor");

Class<?> loadedClass = Class.forName(executorClassName);
Class<? extends Executor> executorClass = loadedClass.asSubclass(Executor.class);

this.executor = executorClass.newInstance();
}

Subclass to capture type arguments


This last one is not so much an idiom as a kludge to get around erasure. Most people who use generics in their code eventually get bitten by this problem, as I already bitched about before. Anyway, sometimes one way to get around the information loss is to subclass the parametrized type. This is because, unlike an instance of a generic type, a subclass does retain type argument information. For an example, see the problem recently posted by Ted Neward and my proposal for a "solution" (its the last one). A much more sophisticated example, including reflection, can be found on this Caelum blog post (it is in portuguese, but the code is understandable).
[Edit: one more item:]

Generic Wrapper


I guess I can't properly call this one an idiom, since I only saw it once. I'm talking about the java.sql.Wrapper interface in jdbc4. It is s a 2-method interface: isWrapperFor(Class<?> iface) and <T> T unwrap(Class<T> iface). It exists to expose extensions to a predefined API in a typesafe manner. I would serioulsy consider something like this when implementing a public extensible API/SPI.
[/Edit]

Wednesday, September 20, 2006

Arrays, genéricos e o maldito compilador (e uma errata)

Há um tempinho eu postei aqui uma dica que deveria facilitar a construção de listas e maps em Java. A idéia básica era escrever uma classe utilitária com métodos estáticos usando varargs e genéricos que depois seriam importados (via static imports) nas classes clientes. Algo assim:


public class CollectionUtils {
public static List listWith(T... elements) {
return Arrays.asList(elements);
}
...
}

Isso até que funciona direto, mas não posso dizer o mesmo sobre a implementação do mapWith. Este método retorna um java.util.Map criado a partir de uma série de pares chave-valor. Cada par é representado por um objeto da classe Map.Entry<K,V> criado usando outro método estático. Assim um uso do mapWih poderia ser:

Map<NumeroNatural, String> numeros = mapWith(pair(ZERO, "0"), pair(ONE, "1"));

Para programar o mapWith eu usei o mesmo truque do listWith, receber os argumentos (os pares) via varargs:

public static <K, V> Map<K, V> mapWith(Map.Entry<K, V>... entries) {
HashMap<K, V> map = new HashMap<K, V>();
for (Map.Entry<K, V> eachEntry : entries)
map.put(eachEntry.getKey(), eachEntry.getValue());
return map;
}

Essa definição de método compila normalmente, mas todas as chamadas à ele receberão um warning do compilador avisando que um array genérico está sendo criado. "Huh? Mas eu não estou criando porcaria de array nenhum!", foi o que eu respondi para o compilador. Depois de me assegurar que ninguém me viu conversando com o javac.exe, que aliás é um interlocutor bem antipático, pesquisei um pouco e descobri que varargs no Java 5 usa arrays por baixo do pano. "Ok, mas qual é o problema de criar um array de tipo genérico?". Bom, vamos por partes, como diria o Leibniz. Primeiro precisamos lembrar que arrays são covariantes no tipo do seu elemento; veja:

String[] sa = new String[10];
Object[] oa = sa;
oa[0] = new Integer(5);

Esse trecho de código compila, mas a última linha atira uma exceção (ArrayStoreException) em tempo de execução. Ou seja, a VM precisa testar se o tipo do array é adequado ao tipo de um objeto sendo inserido nele. Agora, pense nesse trecho:

Class<String>[] ca = new Class<String>[10];
Object[] oa = ca;
ca[0] = new Integer(8);

Aqui, o compilador reclama já na primeira linha que não consegue criar um array de Class<String>. E ele não consegue por um detalhe da implementação de generics no Java: a técnica escolhida para especificar tipos genéricos, chamada "Erasure", remove as informações sobre os parâmetros de tipo (as coisas dentro de <>) ao produzir o bytecode. Como a linguagem não teria informação suficiente para fazer as verificações necessárias quando da inserção de elementos no array, a solução adotada é simplesmente proibir arrays de tipos genéricos.

Agora vou fazer como todo bom mau programador e botar a culpa na linguagem por um bug que eu escrevi. Começando pela escolha de implementar generics via erasure, que significou sacrificar naturalidade em nome da tal "migration compatibility". Volta e meia acontece de eu escrever algum statement que parece perfeitamente inocente e o compilador me chama de burro (ou quase isso). Outra decisão que não me agradou foi a de usar arrays como base dos varargs, em vez de algo menos capenga como Iterable ou Collection. E minha última reclamação é sobre a covariância dos arrays, que enfraquece a tipagem estática a troco de nada (alguém sabe de um bom caso de uso para arrays covariantes?).

Sunday, June 04, 2006

Stupid Tiger Tricks

[EDIT 22-09-2006: There is a bug on the mapWith code below. I explain what happened here.]

One of the things that bugs me about Java is that it lacks literal constructs for creating lists and maps*. This, coupled with the profusion of casts, can lead to APIs prefering arrays over collections, which are otherwise much easier to handle. Java 5 (Tiger) brought generics, helping to minimize all those annoying casts, but the verbosity for initializing collections is still an issue. Here is the result of a quick hack to try and improve things a bit:


public class Web2dot0 {
private List<String> buzzwords =
listWith("mashup", "AJAX", "bottom-up", "tagging");
private Map<Integer, String> strategy =
mapWith(pair(1, "Pretty AJAX UI"), pair(3, "profit!"));
...
}

This was implemented using an utility class with the following static members:

public class CollectionUtils {
public static <E> List<E> listWith(E... items) {
return Arrays.asList(items);
}
public static <K, V> Map<K, V> mapWith(Map.Entry<K, V>... entries) {
HashMap<K, V> map = new HashMap<K, V>();
for (Map.Entry<K, V> eachEntry : entries)
map.put(eachEntry.getKey(), eachEntry.getValue());
return map;
}
public static <K, V> Map.Entry<K, V> pair(K key, V val) {
return new ImmutablePair<K, V>(key, val);
}
public static final class ImmutablePair<K, V> implements Map.Entry<K,V> {...}
...
}

The listWith(), mapWith() and pair() methods were then static imported in the client class.

* And now the geniouses at the JCP want to create XML literals. That reminds me of a comment I read in Taenembaun's computer organization book, saying that if programmers could have their way in the chip design process, opperations like branchAndDoPayroll would be part of the ISA.

Thursday, December 08, 2005

Semáfaros e smalltalk.

Eu sou um pedestre convicto, pelo menos até eu mudar de idéia. Atravesso o campus da USP todo dia sobre as minhas duas pernas, cruzando as largas avenidas e as famosas rotatórias. Atravesso olhando para os dois lados, pois aparentemente esse layout viário é como um convite para os motoristas descarregarem suas frustrações no acelerador acertando, se tiverem sorte, um estudante ou dois no caminho.

Depois de muita enrolação, a prefeitura do campus resolveu o assunto instalando uma meia dúzia de semáfaros para o rebanho de alunos atravessar sem ser abatido. Eu deveria estar contentíssimo com o incremento na minha probabilidade de sobreviver à USP. Mas não. Eu odiei esses semáfaros. E não é porque eu tenho algum desejo inconsciente de comprar um carro veloz e sair atropelando polianos por aí.

Eu não gostei dos semáfaros porquê eles são, bem, feios. Não porquê poluem a paisagem ou outra viadagem desse tipo. São feios porque estragam um sistema que era belo. A beleza do trânsito organizado puramente pela combinação desses dois elementos, avenidas e rotatórias, é corrompida pelos sinais como se alguém escarrasse num Mondrian.

Voltando à vaca fria, admito que ainda não consegui uma resposta satisfatória sobre "o que é ciência da computação", mas tenho a impressão que a resposta envolve esse tipo de beleza. A criação de estruturas é uma constante na prática matemática moderna, mas o apreço ao minimalismo e à composibilidade me parecem marcas características da Ciência da Computação.

Um ótimo exemplo é a linguagem Lisp, onde todas as computações são funções e todo dado é uma lista. Outro exemplo é Smalltalk, onde tudo são objetos que se comunicam pela troca de mensagens. E como ficam as linguagens usadas por seres humanos normais? Retomando a analogia, Java parece um monte de semáfaros enfiados no pobre Smalltalk. E, embora eu nunca tenha programado em C++, ele me lembra um pouco o metrô de tokyo...