Annotation + OO

7 respostas
Marky.Vasconcelos

Olá… estou tentando implementar algo com Annotations… estava tudo certo na minha cabeça… mas quando vi… não é possivel usar Classes como parametro na Annotation… apenas primitive types, Strings e Enums.

Então o que eu queria era ter mais ou menos o seguinte.

package mark.utils.el.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Resolvable {
	String columnName() default "";
                Formatter formatter();
	HandlerType handler() default HandlerType.FIELD_HANDLER;
}

public interface Formatter {
	public String format(Object obj);
	public Object parse(String obj);
}

Mas não é possivel ter o Formatter… o eclipse acusa o seguinte:

Invalid type Formatter for the annotation attribute Resolvable.formatter; only primitive type, String, Class, annotation, enumeration are permitted or 1-dimensional arrays thereof

Tem algum modo para eu ter o resultado que eu espero?

Eu não quero deixar com Enums como eu fiz para o HandlerType pois o Formatter é uma classe que varia muito mais.

ty all
[]'s

7 Respostas

S

Kra, o qi vc quer ali eh indicar qual Formatter a ser usado nao eh?
Entao, passa simplesmente um Class ali que indica a classe do Formatter.

Dai qndo vc pegar sua annotation por reflexao vc pega o class do formatter e da um newInstance nele, pronto.

Marky.Vasconcelos

Nossa. agora que eu pensei… nem teria como eu passar um objeto lá mesmo… já que vou ter um objeto estatico que é uma instancia desse formatter vou poder passar o .class.

Vou tentar… vlw.

Marcelo_FS

Sagatiba:
Kra, o qi vc quer ali eh indicar qual Formatter a ser usado nao eh?
Entao, passa simplesmente um Class ali que indica a classe do Formatter.

Dai qndo vc pegar sua annotation por reflexao vc pega o class do formatter e da um newInstance nele, pronto.

Ou passa uma String e usa Class.forName :stuck_out_tongue:

victorwss

Você pode sim usar classes. Tenta isso:

package mark.utils.el.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Resolvable {
    String columnName() default "";
    Class<? extends Formatter> formatter();
    HandlerType handler() default HandlerType.FIELD_HANDLER;
}

public interface Formatter {
    public String format(Object obj);
    public Object parse(String obj);
}

Ou, se você precisa da instância do Formatter, e não da classe, tente isso:

package mark.utils.el.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Resolvable {
    String columnName() default "";
    Class<? extends FormatterFactory> formatter();
    HandlerType handler() default HandlerType.FIELD_HANDLER;
}

public interface Formatter {
    public String format(Object obj);
    public Object parse(String obj);
}

public interface FormatterFactory {
    public Formatter getFormatter();
}
Marky.Vasconcelos

É que eu teria mais ou menos o seguinte código:

private static final Formatter BASIC_FORMATTER = new Formatter(){//implementação};

//Dai eu queria poder passar esse objeto..
@Resolvable(formatter=BASIC_FORMATTER)
private String string;

Eu tive que deixar o .class mesmo e criei classes que implementão Formatter invés de criar essas anonymous class…

Eu não queria ter que dar um newInstance… mas como tudo que estou fazendo nesse meu projeto auxiliar é baseado em Reflection… isso não é um problema.

victorwss
Mark_Ameba:
É que eu teria mais ou menos o seguinte código:
private static final Formatter BASIC_FORMATTER = new Formatter(){//implementação};

//Dai eu queria poder passar esse objeto..
@Resolvable(formatter=BASIC_FORMATTER)
private String string;

Eu tive que deixar o .class mesmo e criei classes que implementão Formatter invés de criar essas anonymous class..

Eu não queria ter que dar um newInstance.. mas como tudo que estou fazendo nesse meu projeto auxiliar é baseado em Reflection.. isso não é um problema.

Você pode fazer assim:
package xxx;

import java.lang.ref.WeakReference;
import java.util.Map;
import java.util.WeakHashMap;

public class FormatterCache {
    private static final Map<Class<? extends Formatter>, WeakReference<Formatter>> FORMATTERS =
        new WeakHashMap<Class<? extends Formatter>, WeakReference<Formatter>>();

    /**
     * Construtor privado. Esta classe não é instanciável.
     */
    private FormatterCache() {}

    public synchronized static <E extends Formatter> E getFormatter(Class<E> classe) {
        if (classe == null) throw new IllegalArgumentException();

        @SuppressWarnings("unchecked") WeakReference<E> wr = (WeakReference<E>) FORMATTERS.get(classe);
        if (wr == null) return popular(classe);
        E format = wr.get();
        return format != null ? format : popular(classe);
    }

    private static <E extends Formatter> E getFormatter(Class<E> classe) {
        E format = classe.newInstance();
        // Ou então use classe.getConstructor().newInstance() caso o construtor possa lançar exceções
        // ou deva receber parâmetros.

        FORMATTERS.put(classe, new WeakReference<E>(format));
        return format;
    }
}
Daí tudo que você tem que fazer para pegar o Formatter é chamar o método getFormatter() passando a classe que você leu da annotation. Já vai fazer cache sem atrapalhar o coletor de lixo. :)
Marky.Vasconcelos

Gostei… e eu não conhecia essa WeakReference…

Eu estava fazendo bem simples mesmo.

Resolvable resolvable = field.getAnnotation(Resolvable.class);
				String fieldName = field.getName();

				String colName = resolvable.columnName();

				FieldResolver resolver = new FieldResolver(clazz, fieldName,
						colName, resolvable.handler().getHandler());
				try {
					resolver.setFormatter(resolvable.formatter().newInstance());
				} catch (InstantiationException e) {
					throw new RuntimeException(e);
				} catch (IllegalAccessException e) {
					throw new RuntimeException(e);
				}

Valeu… eu estava pensando em implementar um Cache pouco tempo antes de voce postar. :smiley:

Mas antes de usar seu código vou estudar as classes WeakReference e WeakHashMap que eu não conhecia.

Criado 12 de fevereiro de 2009
Ultima resposta 17 de fev. de 2009
Respostas 7
Participantes 4