Injeção de Valores usando Reflection e Annotation em Java (Testes Unitários) - Parte 05

17. novembro 2011 00:10 by BBranquinho in Annotation, Java, Reflection, Tutoriais  //  Tags: , , ,   //   Comentários (0)

Este é o último post que trata da injeção de valores usando reflexão e anotação.

É importante lembrar que este projeto pode ser baixado em http://iar.codeplex.com/

Para finalizar nosso trabalho foram criados alguns testes unitários que mostram o uso da injeção de valores em algumas classes. Existem diversos cenários em que este processo pode ser aplicado. Sendo assim, apenas alguns exemplos foram mostrados para demonstrar a abrangência do trabalho.

Um exemplo de classe com as anotações criadas é mostrado a seguir na classe PrivateStub03.

package br.com.wpattern.annotation.test.stub;

import java.util.Date;

import br.com.wpattern.annotation.WPatternClass;
import br.com.wpattern.annotation.WPatternField;
import br.com.wpattern.annotation.WPatternValue;

@WPatternClass(description="Private Stub 03")
public class PrivateStub03 {

	@WPatternField(name="PARAM01")
	private boolean booleanParameter;

	@WPatternField(name="PARAM02", values={ @WPatternValue(value="1"), @WPatternValue(value="2"),  @WPatternValue(value="3"), @WPatternValue(value="4") })
	private int intParameter;

	@WPatternField(name="PARAM03")
	protected long longParameter;

	@WPatternField(name="PARAM04")
	protected char charParameter;

	@WPatternField(name="PARAM05")
	public double doubleParameter;

	@WPatternField(name="PARAM06")
	public float floatParameter;

	@WPatternField(name="PARAM07")
	public Date dateParameter;

	@Override
	public String toString() {
		return "PrivateStub03 [booleanParameter=" + this.booleanParameter
				+ ", intParameter=" + this.intParameter + ", longParameter="
				+ this.longParameter + ", charParameter=" + this.charParameter
				+ ", doubleParameter=" + this.doubleParameter + ", floatParameter="
				+ this.floatParameter + ", dateParameter=" + this.dateParameter + "]";
	}

}

Na classe PrivateStub03 existe a demonstração do uso das anotações, incluindo a validação dos valores que são aceitados em um dos parâmetros. O teste unitário exibido no próximo código demonstra a injeção dos valores para a classe PrivateStub03.

private final Logger logger = Logger.getLogger(this.getClass());

	private MapFields mapFields;

	@Before
	public void startUp() {
		this.mapFields = new MapFields();

		try {
			this.mapFields.AddField("PARAM01", "true");
			this.mapFields.AddField("PARAM02", "4");
			this.mapFields.AddField("PARAM03", "6");
			this.mapFields.AddField("PARAM04", "c");
			this.mapFields.AddField("PARAM05", "5.45");
			this.mapFields.AddField("PARAM06", "9.78");
			this.mapFields.AddField("PARAM07", "01-01-2000 01:01:01");
		} catch (MapFieldException e) {
			this.logger.error(e.getMessage());
			Assert.fail(e.getMessage());
		}
	}

	@Test
	public void privateStub03_testAllInjection_success() {
		this.logger.debug("Test injection of PrivateStub03.");

		PrivateStub03 instanceObject = new PrivateStub03();

		try {
			InjectorManager.injectAllValues(instanceObject, this.mapFields);
		} catch (InjectionException e) {
			this.logger.error(e.getMessage());
			Assert.fail(e.getMessage());
		}

		this.logger.debug(instanceObject.toString());
	}

O resultado da execução deste teste é:

17-11-2011 02:17:06,587; [main]; DEBUG; br.com.wpattern.annotation.test.AnnotationTest;  - Test injection of PrivateStub03.

17-11-2011 02:17:06,777; [main]; DEBUG; br.com.wpattern.annotation.test.AnnotationTest;  - PrivateStub03 [booleanParameter=true, intParameter=4, longParameter=6, charParameter=C, doubleParameter=5.45, floatParameter=9.78, dateParameter=Sat Jan 01 01:01:01 BRST 2000]

Como podemos observar os valores foram automaticamente injetados nas variáveis.

O próximo vídeo mostra a implementação e a execução dos testes unitários.

Foi um prazer poder apresentar este trabalho.

Até o próximo estudo, abraços.

Injeção de Valores usando Reflection e Annotation em Java (Injeção e Validação dos Valores) - Parte 04

16. novembro 2011 23:51 by BBranquinho in Annotation, Java, Reflection, Tutoriais  //  Tags: , , ,   //   Comentários (0)

Neste post irei tratar da injeção dos valores e da validação dos parâmetros presentes no MapFields. Este trabalho continua os textos apresentados anteriormente.

É importante lembrar que este projeto pode ser baixado em http://iar.codeplex.com/

Existem duas classes usadas para realizar a injeção dos valores, sendo elas: ValidatorManager e InjectorManager. A classe ValidatorManager gerencia a validação das anotações. Essa validação é bem simples e corresponde a um simples exemplo de como trabalhar com as anotações. A classe InjectorManager realiza a injeção dos valores nas variáveis que estão anotadas. A seguir são mostradas estas classes.

package br.com.wpattern.annotation.injection;

import java.lang.reflect.Field;
import java.util.Date;

import br.com.wpattern.annotation.WPatternField;
import br.com.wpattern.annotation.exception.InjectionException;
import br.com.wpattern.annotation.util.ErrorMessages;

class ValidatorManager {

	//=====================================================================================
	// PUBLIC METHODS
	//=====================================================================================

	public static void validateFields(Object objectInstance) throws InjectionException {
		Class<?> objectClass = objectInstance.getClass();

		Field[] fields = objectClass.getDeclaredFields();

		for (Field field : fields) {
			WPatternField annotationField = field.getAnnotation(WPatternField.class);

			if (annotationField != null) {
				if (annotationField.required()) {
					if (!isValidRequeridField(field)) {
						throw new InjectionException(String.format(ErrorMessages.FIELD_WITH_INVALID_TYPE,
								annotationField.name(), field.getType()));
					}
				} else if (!isValidNotRequeridField(field)) {
					throw new InjectionException(String.format(ErrorMessages.FIELD_WITH_INVALID_TYPE,
							annotationField.name(), field.getType()));
				}
			}
		}
	}

	//=====================================================================================
	// PRIVATE METHODS
	//=====================================================================================

	private static boolean isValidRequeridField(Field field) {
		return !((field.getType() != int.class) && (field.getType() != long.class) && (field.getType() != boolean.class) &&
				(field.getType() != char.class) && (field.getType() != double.class) && (field.getType() != float.class) &&
				(field.getType() != Date.class));
	}

	private static boolean isValidNotRequeridField(Field field) {
		return !((field.getType() != int.class) && (field.getType() != Integer.class) &&
				(field.getType() != long.class) && (field.getType() != Long.class) &&
				(field.getType() != boolean.class) && (field.getType() != Boolean.class) &&
				(field.getType() != char.class) && (field.getType() != Character.class) &&
				(field.getType() != double.class) && (field.getType() != Double.class) &&
				(field.getType() != float.class) && (field.getType() != Float.class) &&
				(field.getType() != Date.class));
	}

}
package br.com.wpattern.annotation.injection;

import java.lang.reflect.Field;
import java.util.Date;

import br.com.wpattern.annotation.WPatternField;
import br.com.wpattern.annotation.WPatternValue;
import br.com.wpattern.annotation.exception.FormatFieldException;
import br.com.wpattern.annotation.exception.InjectionException;
import br.com.wpattern.annotation.exception.MapFieldException;
import br.com.wpattern.annotation.util.ErrorMessages;
import br.com.wpattern.annotation.util.MapFields;

public class InjectorManager {

	//=====================================================================================
	// PUBLIC METHODS
	//=====================================================================================

	/**
	 * Inject just public fields.
	 * 
	 * @param objectInstance
	 */
	public static void injectValues(Object objectInstance, MapFields mapFields) throws InjectionException {
		ValidatorManager.validateFields(objectInstance);

		Class<?> objClass = objectInstance.getClass();

		Field[] fields = objClass.getFields();

		for (Field field : fields) {
			WPatternField annotationField = field.getAnnotation(WPatternField.class);

			if (annotationField != null) {
				injectValue(field, annotationField, objectInstance, mapFields);
			}
		}
	}

	/**
	 * Inject all types (public, protected, private, final) of fields.
	 * 
	 * @param objectInstance
	 */
	public static void injectAllValues(Object objectInstance, MapFields mapFields) throws InjectionException {
		ValidatorManager.validateFields(objectInstance);

		Class<?> objClass = objectInstance.getClass();

		Field[] fields = objClass.getDeclaredFields();

		for (Field field : fields) {
			WPatternField annotationField = field.getAnnotation(WPatternField.class);

			if (annotationField != null) {
				field.setAccessible(true);

				injectValue(field, annotationField, objectInstance, mapFields);
			}
		}
	}

	//=====================================================================================
	// PRIVATE METHODS
	//=====================================================================================

	private static void injectValue(Field field, WPatternField fieldAnnotation, Object objectInstance, MapFields mapFields) throws InjectionException {
		Object value = null;

		try {
			validateValue(fieldAnnotation, mapFields);

			if ((field.getType() == int.class) || (field.getType() == Integer.class)) {            // INTEGER
				value = mapFields.getIntValue(fieldAnnotation.name());
			} else if ((field.getType() == long.class) || (field.getType() == Long.class)) {       // LONG
				value = mapFields.getLongValue(fieldAnnotation.name());
			} else if ((field.getType() == boolean.class) || (field.getType() == Boolean.class)) { // BOOLEAN
				value = mapFields.getBooleanValue(fieldAnnotation.name());
			} else if ((field.getType() == char.class) || (field.getType() == Character.class)) {  // CHARACTER
				value = mapFields.getCharacterValue(fieldAnnotation.name());
			} else if ((field.getType() == double.class) || (field.getType() == Double.class)) {   // DOUBLE
				value = mapFields.getDoubleValue(fieldAnnotation.name());
			} else if ((field.getType() == float.class) || (field.getType() == Float.class)) {     // FLOAT
				value = mapFields.getFloatValue(fieldAnnotation.name());
			} else if (field.getType() == Date.class) {                                            // DATE
				value = mapFields.getDateValue(fieldAnnotation.name());
			}
		} catch (MapFieldException e) {
			if (fieldAnnotation.required()) {
				throw new InjectionException(e.getMessage(), e);
			}
		} catch (FormatFieldException e) {
			throw new InjectionException(e.getMessage(), e);
		}

		try {
			field.set(objectInstance, value);
		} catch (IllegalArgumentException e) {
			throw new InjectionException(e.getMessage(), e);
		} catch (IllegalAccessException e) {
			throw new InjectionException(e.getMessage(), e);
		}
	}

	private static void validateValue(WPatternField fieldAnnotation, MapFields mapFields) throws MapFieldException, InjectionException {
		if (fieldAnnotation.values().length <= 0) {
			return;
		}

		String value = mapFields.getValue(fieldAnnotation.name());

		for (WPatternValue wPatternValue : fieldAnnotation.values()) {
			if (wPatternValue.value().equalsIgnoreCase(value)) {
				return;
			}
		}

		throw new InjectionException(String.format(ErrorMessages.FIELD_WITH_INVALID_VALUE, fieldAnnotation.name(), value));
	}

}

A injeção dos valores é realizada de acordo com os tipos das variáveis. Se o campo não é requerido a falta do parâmetro no MapFields tem como resultado a injeção de um valor null na variável anotada. Os detalhes deste código são mostrados no vídeo a seguir.

 

Finalizamos o trabalho de injeção neste post. No próximo e último post eu apresento testes unitários para demonstrar o uso da injeção de valores baseado nas anotações.

Até o próximo post.

Injeção de Valores usando Reflection e Annotation em Java (Criando as Exceções e o HashMap) - Parte 03

16. novembro 2011 23:23 by BBranquinho in Annotation, Java, Reflection, Tutoriais  //  Tags: , , ,   //   Comentários (0)

Este post tem o objetivo de continuar o trabalho sobre a injeção de valores usando reflexão e anotações.

O código do projeto é encontrado em:  http://iar.codeplex.com/

Alguns erros podem ocorrer durante o trabalho de injeção de valores. Além disso, problemas de validação das anotações podem ser necessárias. Sendo assim, são criadas algumas exceções para poder tratar tais cenários. São criadas as exceções FormatFieldExceptionInjectionExceptionMapFieldException. Também são definidas algumas mensagens de erro na classe ErrorMessages. A implementação destas classes é muito simples e é mostrado a seguir.

package br.com.wpattern.annotation.exception;

public class FormatFieldException extends Exception {

	private static final long serialVersionUID = 8464144343246315472L;

	public FormatFieldException() {
	}

    public FormatFieldException(String s) {
        super(s);
    }

    public FormatFieldException(Throwable throwable) {
        super(throwable);
    }
    
    public FormatFieldException(String s, Throwable throwable) {
        super(s, throwable);
    }
	
}
package br.com.wpattern.annotation.exception;

public class InjectionException extends Exception {

	private static final long serialVersionUID = 810546994379030324L;

	public InjectionException() {
    }

    public InjectionException(String s) {
        super(s);
    }

    public InjectionException(Throwable throwable) {
        super(throwable);
    }
    
    public InjectionException(String s, Throwable throwable) {
        super(s, throwable);
    }
	
}
package br.com.wpattern.annotation.exception;

public class MapFieldException extends Exception {

	private static final long serialVersionUID = -8531171176826142401L;

	public MapFieldException() {
    }

    public MapFieldException(String s) {
        super(s);
    }

    public MapFieldException(Throwable throwable) {
        super(throwable);
    }
    
    public MapFieldException(String s, Throwable throwable) {
        super(s, throwable);
    }
    
}

As mensagens de erros são colocadas na classe ErrorMessages.

package br.com.wpattern.annotation.util;

public class ErrorMessages {

	public static final String FIELD_CAN_NOT_BE_NULL = "Field [%s] or value [%s] can't be null.";

	public static final String FIELD_INVALID_FORMAT = "Invalid format [%s] of the field [%s].";

	public static final String FIELD_NOT_FOUNDED = "Field [%s] not founded.";

	public static final String FIELD_WITH_INVALID_TYPE = "Field [%s] with invalid type [%s].";

	public static final String FIELD_WITH_INVALID_VALUE = "Field [%s] with invalid value [%s].";

}

Os valores que são injetados estão mapeadas em MapFields. Essa classe armazena um grupo de valores baseados em uma chave. Por exemplo, esta classe representa um um conjunto de valores presentes em um arquivo de configuração. A seguir é exibida a implementação desta classe.

package br.com.wpattern.annotation.util;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import br.com.wpattern.annotation.exception.FormatFieldException;
import br.com.wpattern.annotation.exception.MapFieldException;

public class MapFields {

	private final Map<String, String> mapOfValues = new HashMap<String, String>();

	public void AddField(String name, String value) throws MapFieldException {
		if ((name == null) || (value == null)) {
			throw new MapFieldException(String.format(ErrorMessages.FIELD_CAN_NOT_BE_NULL, name, value));
		}

		this.mapOfValues.put(name.toUpperCase(), value.toUpperCase());
	}

	public String getValue(String name) throws MapFieldException {
		String value = this.mapOfValues.get(name);

		if (value == null) {
			throw new MapFieldException(String.format(ErrorMessages.FIELD_NOT_FOUNDED, name));
		}

		return value;
	}

	public Integer getIntValue(String name) throws MapFieldException, FormatFieldException {
		String value = getValue(name);

		try {
			return Integer.parseInt(value);
		} catch (NumberFormatException e) {
			throw new FormatFieldException(String.format(ErrorMessages.FIELD_INVALID_FORMAT, value, name), e);
		}
	}

	public Long getLongValue(String name) throws MapFieldException, FormatFieldException {
		String value = getValue(name);

		try {
			return Long.parseLong(value);
		} catch(NumberFormatException e) {
			throw new FormatFieldException(String.format(ErrorMessages.FIELD_INVALID_FORMAT, value, name), e);
		}
	}

	public Double getDoubleValue(String name) throws MapFieldException, FormatFieldException {
		String value = getValue(name);

		try {
			return Double.parseDouble(value);
		} catch(NumberFormatException e) {
			throw new FormatFieldException(String.format(ErrorMessages.FIELD_INVALID_FORMAT, value, name), e);
		}
	}

	public Float getFloatValue(String name) throws MapFieldException, FormatFieldException {
		String value = getValue(name);

		try {
			return Float.parseFloat(value);
		} catch(NumberFormatException e) {
			throw new FormatFieldException(String.format(ErrorMessages.FIELD_INVALID_FORMAT, value, name), e);
		}
	}

	public Boolean getBooleanValue(String name) throws MapFieldException, FormatFieldException {
		String value = getValue(name);

		try {
			return Boolean.parseBoolean(value);
		} catch(NumberFormatException e) {
			throw new FormatFieldException(String.format(ErrorMessages.FIELD_INVALID_FORMAT, value, name), e);
		}
	}

	public Character getCharacterValue(String name) throws MapFieldException, FormatFieldException {
		String value = getValue(name);

		if (value.length() != 1) {
			throw new FormatFieldException(String.format(ErrorMessages.FIELD_INVALID_FORMAT, value, name));
		}

		try {
			return value.charAt(0);
		} catch(NumberFormatException e) {
			throw new FormatFieldException(String.format(ErrorMessages.FIELD_INVALID_FORMAT, value, name), e);
		}
	}

	public Date getDateValue(String name) throws MapFieldException, FormatFieldException {
		String value = getValue(name);

		SimpleDateFormat formater = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");

		try {
			return formater.parse(value);
		} catch(ParseException e) {
			throw new FormatFieldException(String.format(ErrorMessages.FIELD_INVALID_FORMAT, value, name), e);
		}
	}

}

Os métodos do MapFields são responsáveis por extrair os valores com os tipos específicos de acordo com o método chamado.

O vídeo a seguir mostra com detalhes os códigos apresentados neste post.

 

Com este vídeo finalizamos nosso trabalho das exceções.

 

Até o próximo post pessoal, abraços.

Injeção de Valores usando Reflection e Annotation em Java (Criando as Annotations) - Partes 01 e 02

16. novembro 2011 21:51 by BBranquinho in Annotation, Java, Reflection, Tutoriais  //  Tags: , , ,   //   Comentários (0)


O objetivo deste post é de criar Annotations (Anotações) em java e usando Reflection (Reflexão) realizar a injeção de valores em variáveis.

O código do projeto é encontrado em:  http://iar.codeplex.com/

As variáveis que terão os valores injetados estão estão todas anotadas. Serão criadas 3 anotações, sendo: @WPatternClass, @WPatternField e @WPatternValue.

@WPatternClass é usado apenas para anotar a classe, sendo apenas um exemplo de anotação. A anotação @WPatternField é aplicada sobre variáveis de escopo de classe. Por último, @WPatternValue é uma anotação usada dentro de @WPatternField e é responsável por determinar os valores aceitáveis pela variável anotada.

A figura exibida no início do post mostra as principais classes do projeto, incluindo as anotações.

O código responsável por criar as anotações é mostrado a seguir.

package br.com.wpattern.annotation;

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

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface WPatternClass {

	String description() default "";

}
package br.com.wpattern.annotation;

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

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface WPatternField {

	String name();

	boolean required() default true;

	WPatternValue[] values() default { };

}

 

package br.com.wpattern.annotation;

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

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface WPatternValue {

	String value();
}

 

Os vídeos mostrado a seguir explicam com detalhes o projeto e as anotações.

Parte 01

 

Parte 02

 

Até o próximo post pessoal.

 

Abraços.

WPattern

O objetivo deste blog é de disponibilizar os resultados dos meus estudos. Não será tratada apenas uma tecnologia ou área, mas qualquer tópico que seja interessante e possa contribuir com a comunidade de desenvolvedores, comunidade científica e meus alunos. Entretanto, meus trabalhos sempre estão voltado principalmente para as tecnologias .NET, Java e C/C++.

Posts Recentes

Google Translator

JetBrains

JetBrains: Ferramentas de desenvolvimento com .NET.

ReSharper: Excelente ferramenta para .NET.