Mostrando postagens com marcador Java. Mostrar todas as postagens
Mostrando postagens com marcador Java. Mostrar todas as postagens

sábado, 12 de junho de 2010

Apache Commons: Lang

Continuando a série sobre as bibliotecas apache commons, Este post irá se aprofundar nos componentes da biblioteca Lang, cujo principal objetivo é estender as funcionalidades das classes do pacote java.lang. Além disso, a commons Lang inclui componentes de uso comum a outras bibliotecas.

Existem vários componentes do tipo “XXXUtils” na biblioteca commons Lang. Seus métodos, estáticos e autossuficientes, funcionam como funções globais presentes em outras tecnologias.

Devido a diversidade dos componentes desta biblioteca, examinaremo-os por categoria de acordo com as funcionalidades que julguei mais interessantes:

Manipulação de Strings

Suporte a manipulação de String é, sem dúvida, o ponto forte desta biblioteca. Existe uma série de componentes com este propósito, sendo os principais:
  • StringUtils - Encapsula uma série de funcionalidades null-safe de propósito geral que atuam sobre Strings. Minhas favoritas:
    • isEmpty/isBlank - Verifica se uma string contém texto. Uma string empty (vazia) seria o equivalente a “” e uma string blank (branca) cotém apenas caracteres brancos “    ”.
    • upperCase/lowerCase/swapCase/capitalize/uncaptalize - Mudam a capitalização de uma String. Atenção para o método captalize que coloca em caixa alta apenas o primeiro caractere. Nice hum?
    • isAlpha/isNumeric/isWhitespace/isAsciiPrintable - Faz verificações sobre uma string. IsNumeric é bem legal, mas seria mais útil se pudéssemos aferir sobre o tipo de numérico, algo como isInteger ou isShort.
    • abbreviate - Faz abreviação de uma string usando reticências.
    • difference - Compara duas Strings, retornando suas diferenças.
  • RandomStringUtils - Ajuda na criação de string randômicos, úteis na geração de senhas, por exemplo.
  • WordUtils  - Contém métodos que manipulam palavras de um texto, seja obtendo as iniciais (initials) ou colocando-as em caixa alta (captalize)
  • StrSubstitutor – Substitui variáveis em uma string por valores pré-definidos.

Exemplos StringUtils

String nullString = null;
String emptyString = "";
String blankString = "  ";
String regularString = "apache commons lang";

StringUtils.isEmpty(nullString); // true
StringUtils.isEmpty(emptyString);// true
StringUtils.isEmpty(blankString);// false
StringUtils.isEmpty(regularString);// false

StringUtils.isBlank(nullString); // true
StringUtils.isBlank(emptyString); // true
StringUtils.isBlank(blankString); // true
StringUtils.isBlank(regularString); // false


String lowcase = "lang";
  String uppercase = "LANG";
  String nullString = null;

  StringUtils.upperCase(lowcase); // LANG
  StringUtils.upperCase(uppercase); // LANG
  StringUtils.upperCase(nullString); // null

  StringUtils.lowerCase(lowcase); // lang
  StringUtils.lowerCase(uppercase);// lang
  StringUtils.lowerCase(nullString);// null

  StringUtils.swapCase(lowcase); // LANG
  StringUtils.swapCase(uppercase);// lang
  StringUtils.swapCase(nullString);// null

  StringUtils.capitalize(lowcase); // Lang
  StringUtils.capitalize(uppercase);// LANG
  StringUtils.capitalize(nullString);// null

  StringUtils.uncapitalize(lowcase); // lang
  StringUtils.uncapitalize(uppercase);// lANG
  StringUtils.uncapitalize(nullString);// null


String onlyAlphaString = "abcd";
  String onlyNumericString = "123";
  String mixString = "a1b 2c3";
  String blackString = "  ";

  StringUtils.isAlpha(onlyAlphaString); // true
  StringUtils.isAlpha(onlyNumericString); // false
  StringUtils.isAlpha(mixString); // false
  StringUtils.isAlpha(blackString); // false

  StringUtils.isNumeric(onlyAlphaString); // false
  StringUtils.isNumeric(onlyNumericString); // true
  StringUtils.isNumeric(mixString); // false
  StringUtils.isNumeric(blackString); // false

  StringUtils.isWhitespace(onlyAlphaString); // false
  StringUtils.isWhitespace(onlyNumericString); // false
  StringUtils.isWhitespace(mixString); // false
  StringUtils.isWhitespace(blackString); // true




String bigString = "this string is too big to fit you application's grid";

  String smallerString = StringUtils.abbreviate(bigString, 30);

  System.out.println(smallerString); // this string is too big to f...






String stringOne = "Luke, I'm your father!";
String stringTwo = "Luke, I'm your uncle!"; 
StringUtils.difference(stringOne, stringTwo); //uncle!
Exemplo WordUtils

String name = "carla gabriele batista dos santos";
  
  WordUtils.initials(name);//cgbds
  WordUtils.capitalize(name);//Carla Gabriele Batista Dos Santos



Exemplo StrSubstitutor

Map variablesMap = new HashMap();
   variablesMap.put("var1", "first variable");
   variablesMap.put("var2", "second variable");
   String templateString = "Let's print ${var1} and ${var2}";
   StrSubstitutor sub = new StrSubstitutor(variablesMap);
   String resolvedString = sub.replace(templateString);
   
System.out.println(resolvedString); //Let's print first variable and second variable



ObjectUtils e ClassUtils

Estes componentes merecem uma menção honrosa a parte. ObjectUtils pode ser usado para efetuar operações corriqueiras como comparações e obtenções de hashCode de forma null-safe. ClassUtils contém método para obtenção de uma série de informações a respeito de uma ou mais classes, como as interfaces que ela implementa e superclasses que estende, o pacote no qual se localiza, verificar se é uma classe interna, se pode ser assinalada para uma referência de um outro tipo, entre outros, e tudo isso de forma null-safe.

Integer intVariable = null;
  Integer anotherIntVariable = 5;
  
  ObjectUtils.hashCode(intVariable); //0
  
  ObjectUtils.toString(intVariable); //""
  
  ObjectUtils.equals(intVariable, anotherIntVariable); //false
  
 ObjectUtils.max(intVariable, anotherIntVariable); // 5 (podia ser genérico né?)



System.out.println(ClassUtils.getAllInterfaces(Integer.class)); // [interface java.lang.Comparable, interface java.io.Serializable]
  
  ClassUtils.getAllSuperclasses(Integer.class); //[class java.lang.Number, class java.lang.Object]
  
  ClassUtils.getPackageName(Integer.class); //java.lang
  
  ClassUtils.isInnerClass(Integer.class); //false
  
  ClassUtils.isInnerClass(Integer.class); //false

  ClassUtils.isAssignable(Integer.class, Number.class); //true





Builders

Esta categoria inclui 4 componentes que auxiliam na implementação de 4 métodos básicos, em especial para classes de domínio, de qualquer sistema: EqualsBuilder, HashCodeBuilder, CompareToBuilder e toStringBuilder. Através delas é possível obter uma implementação correta e eficiente dos métodos equals, hashCode, compareTo e toString, respectivamente, apenas informando as propriedades envolvidas.

Além disso, todos os componentes possuem métodos alternativos que permitem a execução de forma reflexiva, incluindo todas as propriedades. Nestes casos, é possível especificar propriedades a serem ignoradas, se for o caso.

public class Person implements Comparable {

 private String name;

 private Integer age;

 private Float weight;

 private Float height;

 private Person mother;

 /**
  * São consideradas iguais duas pessoas com mesmo nome, idade e filhas da
  * mesma mãe.
  */
 @Override
 public boolean equals(Object obj) {
  if (this == obj)
   return true;
  if (obj == null)
   return false;
  if (getClass() != obj.getClass())
   return false;
  Person other = (Person) obj;

  return new EqualsBuilder().append(age, other.age).append(mother,
    other.mother).append(name, other.name).isEquals();

  // Implementação alternativa que usa reflexão. É preciso informar os
  // campos a serem ignorados na compração para manter equivalência com a
  // implementação a cima.
  //
  // return EqualsBuilder.reflectionEquals(this, obj, Arrays.asList(
  // "weight", "height"));

 }

 /**
  * cálculo do hash code consistente com equals.
  */
 @Override
 public int hashCode() {

  return new HashCodeBuilder(17, 37).append(name).append(age).append(
    mother).toHashCode();

  // Implementação alternativa que usa reflexão. É preciso informar os
  // campos a serem ignorados. para manter equivalência com a
  // implementação a cima.
  //
  // return HashCodeBuilder.reflectionHashCode(this,
  // Arrays.asList("weight",
  // "height"));

 }

 /**
  * Define a representação em forma de String de um objeto da classe Person
  */
 @Override
 public String toString() {

  return new ToStringBuilder(this).append("name", name)
    .append("age", age).toString();

  // Implementação alternativa que usa reflexão. Não é possível informar
  // atributos a serem ignorados, portanto esta implementação não é
  // equivalente àquela a cima.
  //
  // return ToStringBuilder.reflectionToString(this);
 }

 /**
  * Determina forma de comparar objetos do tipo Person.
  */
 @Override
 public int compareTo(Person o) {
  return new CompareToBuilder().append(this.name, o.name).append(
    this.age, o.age).toComparison();

  // Implementação alternativa que usa reflexão. É preciso informar os
  // campos a serem ignorados. para manter equivalência com a
  // implementação a cima.
  //
  // return CompareToBuilder.reflectionCompare(this, o,
  // Arrays.asList("weight", "height","mother"));
 }

//getter e setter omitidos
} 

Math

A biblioteca commons lang inclui alguns componentes com funcionalidades matemáticas básicas. (as mais avançadas ficam na bilbioteca Math) Destaque para as classes que representam intervalos numéricos (IntRange, LongRange, FloatRange e DoubleRange), para a classe Fraction, que representa um número fracionário e para NumberUtils, que disponibiliza métodos utilitários interessantes.

IntRange firstRange = new IntRange(0, 10);
  IntRange secondRange = new IntRange(6,13);
  IntRange thirdRange = new IntRange(11,15);
  
  
  firstRange.containsInteger(5); //true
  firstRange.containsInteger(10); //true. ambos liites são inclusivos.
  firstRange.containsInteger(15); // false
  
  secondRange.getMaximumInteger(); //13
  secondRange.getMinimumInteger(); // 6
  
  firstRange.overlapsRange(secondRange); // true
  firstRange.overlapsRange(thirdRange); // false



Outros

Além dos componentes já mencinados, existem alguns outros que vale apena conferir, como aqueles relacioandos a tempo (destque para StopWatch) e para criação de tipe-safes enums que, devido a sua flexibilidade, continuam sendo muito utilizadas apesar das enumerações já terem sido padonizadas na versão 5 da linguagem.

domingo, 23 de maio de 2010

Apache Commons - BeanUtils - English Version

First of all I'd like to apologize for taking so long to update this blog. Lots of work to do, thanks God, but I'll try not to let it happen again.

Apache commons is a project dedicated to create reusable components. But that, of course, you already knew. Today I am inaugurating a series of posts whose goal is to delve into these components by exposing the available features, of which the details are ignored by most developers.

The project is divided into a variety of categories of components (FileUpload, Lang, Net, Collections, etc. ..). This post in particular will focus on just one: BeanUtils. First, however, it's worth reinforcing two important concepts: reflection and Java Beans.

Reflection, Introspection and Intercession

There is some confusion about these terms in the community (particularly in relation to the first two). Being quick and dirty, reflection is one's language's ability to manipulate, at runtime, elements of its own structure, such as classes, methods and properties. Introspection is a special kind of reflection limited to examining those factors, without changing them. Intercession would be just the other side of the coin:  change, at runtime, classes and methods of objects (http://goo.gl/dMZL in portuguese)

Despite the name of the package (java.lang.reflect), what Java provides us is actually just introspection. As we shall see the BeanUtils library tries to provide us with a basic form of intercession.

Java Beans

Java beans are a special type of class, which follow a naming standard defined in a specification (http://goo.gl/3fGL). That's it :P.

BeanUtils

BeanUtils is a library that combines the concepts of introspection and Java Beans, offering components that provide:

  • Access to properties and methods of Java Beans in an easier way, including integrated type conversion.
  • Dynamic definition of beans, a basic form of intercession. 

Access to properties via introspection
For the examples, let us consider the classes  JavaBean and AnotherJavaBean adhering to the Java Beans standards:

package main;

import java.util.List;

public class JavaBean {
 
 private String stringProp;
 
 private Integer intProp;
 
 private List listProp;
 
 private AnotherJavaBean anotherJavaBeanProp;


 public AnotherJavaBean getAnotherJavaBeanProp() {
  return anotherJavaBeanProp;
 }

 public void setAnotherJavaBeanProp(AnotherJavaBean anotherJavaBeanProp) {
  this.anotherJavaBeanProp = anotherJavaBeanProp;
 }

 public String getStringProp() {
  return stringProp;
 }

 public void setStringProp(String stringProp) {
  this.stringProp = stringProp;
 }

 public Integer getIntProp() {
  return intProp;
 }

 public void setIntProp(Integer intProp) {
  this.intProp = intProp;
 }

 public List getListProp() {
  return listProp;
 }

 public void setListProp(List colProp) {
  this.listProp = colProp;
 }

}

package main;

public class AnotherJavaBean {

 private Short shortProp;

 public Short getShortProp() {
  return shortProp;
 }

 public void setShortProp(Short shortProp) {
  this.shortProp = shortProp;
 }

}

To get the value of "stringProp" property of a JavaBean class instance via its getter method using the Java API you need to do something like the code lines below:


public static void main(String[] args) {

  // Creating an instance to be dynamically accessed
  JavaBean beanTest = new JavaBean();
  beanTest.setStringProp("test String");

  // Getter method name. In a more general scenario, this string
  //would have to be assembled dynamically.
  String nameGetter = "getStringProp";

  // Getting the class object of the class to be manipulated.
  Class clazz = JavaBean.class;

  try {

   // Getting instance of the Method class for the method to be invoked.
   Method stringPropGetter = clazz.getMethod(nameGetter);   
   
   //The invoke method of the Method class executes the method.
   String propertyValue = (String) stringPropGetter
     .invoke(beanTest);

   // Printing the value of the property
   System.out.println(propertyValue);

  } catch (SecurityException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (NoSuchMethodException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (IllegalArgumentException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (IllegalAccessException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (InvocationTargetException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

 }


Using the component PropertyUtils to perform the same task, the code looks like this:

/**
  * @param args
  */
 public static void main(String[] args) {

  // Creating an instance to be dynamically accessed
  JavaBean beanTest = new JavaBean();
  beanTest.setStringProp("Test String");

  //We use the property name. The name of the getter is derived internally by the API.
  String propertyName = "stringProp";

  try {
   
   //Getting the property value. Just pass the object and the name of the property.
   String propertyValue = (String) PropertyUtils.getProperty(beanTest,
     propertyName);
   
   // Printing the value of the property
   System.out.println(propertyValue);
   
  } catch (IllegalAccessException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (InvocationTargetException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (NoSuchMethodException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

 }



Besides the more compact code, it is worth noting the smaller number of exceptions to be treated, and how the component takes advantage of the Java Beans' naming standards to automatically derive the name of the getter method for property requested.

Besides access to simple properties, the component PropertyUtils provides facilities to access  indexed properties:

/**
  * @param args
  */
 public static void main(String[] args) {
  //  Creating an instance to be dynamically accessed
  JavaBean beanTest = new JavaBean();
  List list = Arrays.asList(1, 2, 3, 4, 5);
  beanTest.setListProp(list);

  //We use the property name. The name of the getter is derived internally by the API.
  String propertyName = "listProp";

  try {
   // Getting the property value. Just pass the object and the name of the property.
   Integer propertyValue = (Integer) PropertyUtils
     .getIndexedProperty(beanTest, propertyName, 3);

   // Printing the value of the property
   System.out.println(propertyValue);

  } catch (IllegalAccessException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (InvocationTargetException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (NoSuchMethodException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

 }


and nested

/**
  * @param args
  */
 public static void main(String[] args) {
  // Creating an instance to be dynamically accessed
  JavaBean beanTest = new JavaBean();
  AnotherJavaBean anotherBeanTest = new AnotherJavaBean();
  anotherBeanTest.setShortProp((short) 1);
  beanTest.setAnotherJavaBeanProp(anotherBeanTest);

  // We use the property name. The name of the getter is derived internally by the API.
  String nameProperty = "anotherJavaBeanProp.shortProp";
  
  try {
   //Getting the property value. Just pass the object and the name of the property.
   Short propertyValue = (Short) PropertyUtils.getNestedProperty(beanTest, nameProperty);
   
   // Printing the value of the property
   System.out.println(propertyValue);
  } catch (IllegalAccessException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (InvocationTargetException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (NoSuchMethodException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

 }



Besides access them, you can assign values to properties of objects, and you can do it through very similar methods  (including for indexed and nested properties.)

Another interesting feature, provided by the BeanUtils component, is copying properties between objects. Through the methods copyProperty and copyProperties you can copy the value of one or all of the properties of similar name among beans, even if they are to unrelated classes.

public static void main(String[] args) {
  //instantiating beans to copy properties
  JavaBean oneBean = new JavaBean();
  JavaBean otherBean = new JavaBean();

  //assigning values to properties of the first bean
  oneBean.setIntProp(1);
  oneBean.setStringProp("string");
  oneBean.setListProp(Arrays.asList(0, 1, 2));
  
  try {
   
   //copying the properties of the first to the second bean
   BeanUtils.copyProperties(otherBean, oneBean);
   
   //printing the value of the properties of the second bean
   System.out.println(otherBean.getStringProp());
   System.out.println(otherBean.getIntProp());
   System.out.println(otherBean.getListProp());
   
  } catch (IllegalAccessException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (InvocationTargetException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  
  

 }


Speaking of the BeanUtils component, it is worth mentioning it contains methods for accessing and assigning properties just like PropertyUtils, including automatic conversion. The library comes with built in converters and it is possible to register our  own converters in a very simple way.

public class BeanUtilsTest {

 //Class that will convert to a AnotherJavaBean
 public static class AnotherJavaBeanConverter implements Converter {

  //Method gets the class for which the conversion will be done and the value to be converted.
  @Override
  public Object convert(Class arg0, Object arg1) {

   AnotherJavaBean bean = new AnotherJavaBean();
   bean.setShortProp(Short.valueOf(arg1.toString()));

   return bean;
  }

 }

 /**
  * @param args
  */
 public static void main(String[] args) {
  //Creating an instance to be dynamically populated
  JavaBean beanTest = new JavaBean();
  
  //registering converting to AnotherJavaBean
  ConvertUtils.register(new AnotherJavaBeanConverter(),
    AnotherJavaBean.class);

  try {
   // assigning value dynamically. the string "1" will be converted to Integer using the library's standard converter 
   BeanUtils.setProperty(beanTest, "intProp", "1");
   
   //assigning value dinaminamicamente. the integer value 123 is converted using the library's standard converter
   BeanUtils.setProperty(beanTest, "stringProp", 123);
   
   //assigning value dinaminamicamente. the integer value 2 is converted using the convert registered for the class AnotherJavaBean
   BeanUtils.setProperty(beanTest, "anotherJavaBeanProp", 2);

   // Printing the values of the properties of the beanTest
   System.out.println(beanTest.getIntProp());
   System.out.println(beanTest.getStringProp());
   System.out
     .println(beanTest.getAnotherJavaBeanProp().getShortProp());
  } catch (IllegalAccessException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (InvocationTargetException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

 }
} 
Dynamic Beans
Dynamic beans or DynaBeans allow a basic form of intercession: ie dynamic change in structure (properties) of beans.
Here's an example where we create the same bean JavaBean used in previous examples in a dynamic way:

public static void main(String[] args) {

  String nameStringProp = "stringProp";
  String nameIntProp = "intProp";
  String nameListProp = "listProp";
  String nameAnotherJavaBeanProp = "anotherJavaBeanProp";
  String shortPropAtAnotherJavaBean = "anotherJavaBeanProp.shortProp";

 
  
  //Creating a DynaProperty vector. A DynaProperty Instance represents a property in the DynaBean
  DynaProperty[] props = new DynaProperty[] {
    new DynaProperty(nameStringProp, String.class),
    new DynaProperty(nameIntProp, Integer.class),
    new DynaProperty(nameListProp, List.class),
    new DynaProperty(nameAnotherJavaBeanProp, AnotherJavaBean.class) };

 
  
  //Creating a DynaBean class, named "JavaBean" with the above defined properties.
  BasicDynaClass dynaClass = new BasicDynaClass("JavaBean", null, props);

  try {

   
   // Creating an instance of JavaBean
   DynaBean javaBeanTest = dynaClass.newInstance();

   // Assigning values to properties
   javaBeanTest.set(nameStringProp, "Test String");
   javaBeanTest.set(nameIntProp, 200);
   javaBeanTest.set(nameListProp, Arrays.asList(1, 2, 3, 4));
   AnotherJavaBean anotherJavaBean = new AnotherJavaBean();
   anotherJavaBean.setShortProp((short) 13);
   javaBeanTest.set(nameAnotherJavaBeanProp, anotherJavaBean);

   // printing the value of attributes. Note that the dynamic access methods work as expected even with DynaBeans.
   System.out.println(PropertyUtils.getSimpleProperty(javaBeanTest,
     nameStringProp));
   System.out.println(PropertyUtils.getSimpleProperty(javaBeanTest,
     nameIntProp));
   System.out.println(PropertyUtils.getSimpleProperty(javaBeanTest,
     nameListProp));
   System.out.println(PropertyUtils.getNestedProperty(javaBeanTest,
     shortPropAtAnotherJavaBean));

  } catch (IllegalAccessException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (InstantiationException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (InvocationTargetException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (NoSuchMethodException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

 }



It is worth noting the use of classes DynaClass (through its subclass BasicDynaClass) and DynaBean. Another important point is the indistinct use of dynamic access methods we saw earlier.

Besides basic DynaBean (which we saw in the previous example) the library offers other types of DynaBeans such as the ResultSetDynaBeans and RowSetDynaBeans. The most interesting variety of DynaBean, however, is the LazyDynaBean. The main feature of this component is the creation of properties at the time of the assignment (no need to do it previously).

Conclusion

These are therefore the most important components of the apache commons BeanUtils library. Wait soon for other posts about co-sisters libraries!


















segunda-feira, 17 de maio de 2010

Apache Commons - BeanUtils

Primeiramente gostaria de me desculpar pela demora na atualização do blog. Muito trabalho, graças a Deus, mas vou me esforçar para que isso não aconteça novamente.
Apache commons é um projeto apache dedicado a criação de componentes reutilizáveis. Mas isto, é claro, você já sabia. Inauguro hoje uma série de posts cujo objetivo é se aprofundar nestes componentes expondo as funcionalidades disponibilizadas, cujos detalhes são ignorados pela maioria dos desenvolvedores.
O projeto é dividido em uma variedade de categorias de componentes (FileUpload, Lang, Net, Collections, etc..). Este post em particular irá se concentrar em apenas uma: BeanUtils. Primeiramente, no entanto, vale reforçar dois conceitos importantes: reflexão e java beans.
Reflexão, Introspecção e Intercessão
Existe alguma confusão a respeito destes termos na comunidade (em especial em relação aos dois primeiros). Sendo rápido e rasteiro, reflexão é a habilidade de uma linguagem de manipular, em tempo de execução, elementos de suas própria estrutura, como classes, métodos e propriedades. Introspecção é um tipo especial de reflexão limitada a examinar estes elementos, sem alterá-los. Intercessão seria justamente o outro lado da moeda: alteração em tempo de execução de classes e métodos dos objetos (http://goo.gl/dMZL).
A pesar do nome do pacote (java.lang.reflect), o que java nos oferece é na verdade apenas introspecção. Como veremos adiante a biblioteca BeanUtils tenta nos fornecer uma forma básica de intercessão.
Java Beans
Java beans são um tipo especial de classe, que segue um padrão de nomenclatura definido em uma especificação (http://goo.gl/3fGL). Só isso :P.
BeanUtils
BeanUtils é uma biblioteca que alia os conceitos de introspecção e java Beans, disponibilizando componentes que provêem:
  • Acesso a propriedades e métodos de java beans de forma facilitada, incluindo conversão de tipos integrada.
  • Definição dinâmica de beans, uma forma básica de intercessão.
Acesso a Propriedades via Introspecção
Para os exemplos, vamos considerar as classes JavaBean e AnotherJavaBean aderentes aos padrões JavaBeans:


package main;

import java.util.List;

public class JavaBean {
 
 private String stringProp;
 
 private Integer intProp;
 
 private List listProp;
 
 private AnotherJavaBean anotherJavaBeanProp;


 public AnotherJavaBean getAnotherJavaBeanProp() {
  return anotherJavaBeanProp;
 }

 public void setAnotherJavaBeanProp(AnotherJavaBean anotherJavaBeanProp) {
  this.anotherJavaBeanProp = anotherJavaBeanProp;
 }

 public String getStringProp() {
  return stringProp;
 }

 public void setStringProp(String stringProp) {
  this.stringProp = stringProp;
 }

 public Integer getIntProp() {
  return intProp;
 }

 public void setIntProp(Integer intProp) {
  this.intProp = intProp;
 }

 public List getListProp() {
  return listProp;
 }

 public void setListProp(List colProp) {
  this.listProp = colProp;
 }

}


package main;

public class AnotherJavaBean {

 private Short shortProp;

 public Short getShortProp() {
  return shortProp;
 }

 public void setShortProp(Short shortProp) {
  this.shortProp = shortProp;
 }

}





Para obter o valor da propriedade “stringProp” de uma instancia da classe JavaBean através do seu método getter usando a API Java é preciso fazer algo parecido com o código das linhas abaixo:

// Criando uma instancia para ser acessada dinamicamente
  JavaBean beanTeste = new JavaBean();
  beanTeste.setStringProp("String de teste");

  // Nome do metodo getter. Em um cenário mais generalista, esta string
  // teria que ser montada dinamicamente.
  String nomeGetter = "getStringProp";

  // Obtendo o class da classe a ser manipulada.
  Class clazz = JavaBean.class;

  try {

   // Obtendo instância da classe Method para o método a ser invocado.
   Method stringPropGetter = clazz.getMethod(nomeGetter);

   // O método invoke da classe Method executa o método, em uma
   // instancia e com argumentos passados por parâmetro. Neste caso não
   // há argumentos.
   String valorPropriedade = (String) stringPropGetter
     .invoke(beanTeste);

   // Imprimindo no console o valor da propriedade.
   System.out.println(valorPropriedade);

  } catch (SecurityException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (NoSuchMethodException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (IllegalArgumentException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (IllegalAccessException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (InvocationTargetException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

 

Usando o componente PropertyUtils para executar a mesma tarefa, o código fica assim:

// Criando uma instancia para ser acessada dinamicamente
  JavaBean beanTeste = new JavaBean();
  beanTeste.setStringProp("String de teste");

  //Usa-se o nome da propriedade. O nome do getter é derivado internamente pela API.
  String nomePropriedade = "stringProp";

  try {
   
   //Obtendo o valor da propriedade. Basta passar o objeto e o nome da propridade.
   String valorPropriedade = (String) PropertyUtils.getProperty(beanTeste,
     nomePropriedade);
   
   // Imprimindo no console o valor da propriedade.
   System.out.println(valorPropriedade);
   
  } catch (IllegalAccessException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (InvocationTargetException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (NoSuchMethodException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }



Além do código mais compacto, vale observar a quantidade reduzida de exceções a serem tratadas, e o fato do componente tomar vantagem dos padrões de nomenclatura Java Bean para derivar automaticamente o nome do método getter para a propriedade requisitada.
Além de acesso a propriedades simples, o componente PropertyUtils fornece facilidades no acesso a propriedades indexadas:

// Criando uma instancia para ser acessada dinamicamente
  JavaBean beanTeste = new JavaBean();
  List list = Arrays.asList(1, 2, 3, 4, 5);
  beanTeste.setListProp(list);

  //Usa-se o nome da propriedade. O nome do getter é derivado internamente pela API.
  String nomePropriedade = "listProp";

  try {
   // Obtendo o valor da propriedade. Aqui passamos o objeto, o nome da
   // propriedade e indice a ser acessado.
   Integer valorPropiedade = (Integer) PropertyUtils
     .getIndexedProperty(beanTeste, nomePropriedade, 3);

   // Imprimindo no console o valor da propriedade.
   System.out.println(valorPropiedade);

  } catch (IllegalAccessException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (InvocationTargetException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (NoSuchMethodException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }


e aninhadas:

// Criando uma instancia para ser acessada dinamicamente
  JavaBean beanTeste = new JavaBean();
  AnotherJavaBean anotherBeanTest = new AnotherJavaBean();
  anotherBeanTest.setShortProp((short) 1);
  beanTeste.setAnotherJavaBeanProp(anotherBeanTest);

  // Usa-se o nome da propriedade. O nome do getter é derivado
  // internamente pela API.
  String nomePropriedade = "anotherJavaBeanProp.shortProp";
  
  try {
   Short valorPropriedade = (Short) PropertyUtils.getNestedProperty(beanTeste, nomePropriedade);
   
   System.out.println(valorPropriedade);
  } catch (IllegalAccessException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (InvocationTargetException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (NoSuchMethodException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }



Além de acessar, é possível atribuir valores as propriedades dos objetos, de forma muito semelhante a usada para acessar os dados (inclusive para propriedades indexadas e aninhadas.)
Outra funcionalidade interessante, fornecida pelo componente BeanUtils é copia de propriedades entre objetos. Através dos métodos copyProperties e copyProperty é possível copiar o valor de uma ou todas as propriedades de nome semelhante entre beans, mesmo que sejam de classes não relacionadas.

JavaBean oneBean = new JavaBean();
  JavaBean otherBean = new JavaBean();

  oneBean.setIntProp(1);
  oneBean.setStringProp("string");
  oneBean.setListProp(Arrays.asList(0, 1, 2));
  
  try {
   BeanUtils.copyProperties(otherBean, oneBean);
   
   System.out.println(otherBean.getStringProp());
   System.out.println(otherBean.getIntProp());
   System.out.println(otherBean.getListProp());
  } catch (IllegalAccessException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (InvocationTargetException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  


Falando do componente BeanUtils, vale ressaltar ele contém métodos de acesso e atribuição de propriedade semelhantes a PropertyUtils, incluindo conversão automática. A biblioteca vem com converters próprios mais é possível cadastrar os seus próprios de maneira simples.

public class BeanUtilsTest {

 //Classe que fará a conversão para um AnotherJavaBean
 public static class AnotherJavaBeanConverter implements Converter {

  //Método recebe a classe para a qual será feita a conversão e o valor a ser convertido.
  @Override
  public Object convert(Class arg0, Object arg1) {

   AnotherJavaBean bean = new AnotherJavaBean();
   bean.setShortProp(Short.valueOf(arg1.toString()));

   return bean;
  }

 }

 /**
  * @param args
  */
 public static void main(String[] args) {
  //criando instancia a ser populada dinamicamente
  JavaBean beanTest = new JavaBean();
  
  //registrando converter para o AnotherJavaBean
  ConvertUtils.register(new AnotherJavaBeanConverter(),
    AnotherJavaBean.class);

  try {
   // atribuindo valor dinaminamicamente. a String "1" será convertida para Integer usando converters padrão da biblioteca
   BeanUtils.setProperty(beanTest, "intProp", "1");
   
   //atribuindo valor dinaminamicamente. o valor inteiro 123 será convertido usando converters padrão da biblioteca 
   BeanUtils.setProperty(beanTest, "stringProp", 123);
   
   //atribuindo valor dinaminamicamente. o valor inteiro 2 será convertido usando converter registrado para a classe AnotherJavaBean
   BeanUtils.setProperty(beanTest, "anotherJavaBeanProp", 2);

   System.out.println(beanTest.getIntProp());
   System.out.println(beanTest.getStringProp());
   System.out
     .println(beanTest.getAnotherJavaBeanProp().getShortProp());
  } catch (IllegalAccessException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (InvocationTargetException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

 }
}


Beans Dinâmicos
Beans dinâmicos ou DynaBeans possibilitam uma forma básica de intercessão: ou seja mudança dinâmica na estrutura (propriedades) dos beans.
Segue um exemplo onde criamos o mesmo bean JavaBean usado  nos exemplos anteriores de forma dinâmica:

String nomeStringProp = "stringProp";
  String nomeIntProp = "intProp";
  String nomeListProp = "listProp";
  String nomeAnotherJavaBeanProp = "anotherJavaBeanProp";
  String shortPropEmAnotherJavaBean = "anotherJavaBeanProp.shortProp";

  // criando um vetor de DynaProperty, que representa uma propriedade de
  // um DynaBean
  DynaProperty[] props = new DynaProperty[] {
    new DynaProperty(nomeStringProp, String.class),
    new DynaProperty(nomeIntProp, Integer.class),
    new DynaProperty(nomeListProp, List.class),
    new DynaProperty(nomeAnotherJavaBeanProp, AnotherJavaBean.class) };

  // Criando uma classe de DynaBeans, chamada 'JavaBean' com as
  // propriedades definidas a cima.
  BasicDynaClass dynaClass = new BasicDynaClass("JavaBean", null, props);

  try {

   // Criando uma instância de JavaBean
   DynaBean javaBeanTest = dynaClass.newInstance();

   // Atribuindo valores as propriedades
   javaBeanTest.set(nomeStringProp, "string Teste");
   javaBeanTest.set(nomeIntProp, 200);
   javaBeanTest.set(nomeListProp, Arrays.asList(1, 2, 3, 4));
   AnotherJavaBean anotherJavaBean = new AnotherJavaBean();
   anotherJavaBean.setShortProp((short) 13);
   javaBeanTest.set(nomeAnotherJavaBeanProp, anotherJavaBean);

   // imprimindo o valor dos atributos. Note que os métodos de acesso
   // dinâmico funcionam como esperado mesmo com DynaBeans.
   System.out.println(PropertyUtils.getSimpleProperty(javaBeanTest,
     nomeStringProp));
   System.out.println(PropertyUtils.getSimpleProperty(javaBeanTest,
     nomeIntProp));
   System.out.println(PropertyUtils.getSimpleProperty(javaBeanTest,
     nomeListProp));
   System.out.println(PropertyUtils.getNestedProperty(javaBeanTest,
     shortPropEmAnotherJavaBean));

  } catch (IllegalAccessException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (InstantiationException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (InvocationTargetException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (NoSuchMethodException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

Vale observar o uso das classes DynaClass (através de sua subclasse BasicDynaClass) e DynaBean. Outro ponto importante é o uso indistinto dos métodos de acesso dinâmico que vimos anteriormente.
Além de DynaBean básicos (que seriam os do exemplo anterior) a biblioteca disponibiliza outros tipos de DynaBeans, como por exemplo os ResultSetDynaBeans e RowSetDynaBeans. A variedade mais interessante de DynaBean, no entanto, é o LazyDynaBean. A principal característica deste componente é a criação de propriedades no momento da atribuição (não há necessidade de fazer isso previamente).

String nomeStringProp = "stringProp";
  String nomeIntProp = "intProp";
  String nomeListProp = "listProp";
  String nomeAnotherJavaBeanProp = "anotherJavaBeanProp";
  String shortPropEmAnotherJavaBean = "anotherJavaBeanProp.shortProp";

  DynaBean javaBeanTest = new LazyDynaBean();

  //Criando e atribuindo valores as propriedades
  javaBeanTest.set(nomeStringProp, "string Teste");
  javaBeanTest.set(nomeIntProp, 200);
  javaBeanTest.set(nomeListProp, Arrays.asList(1, 2, 3, 4));
  AnotherJavaBean anotherJavaBean = new AnotherJavaBean();
  anotherJavaBean.setShortProp((short) 13);
  javaBeanTest.set(nomeAnotherJavaBeanProp, anotherJavaBean);

  try {
   // imprimindo o valor dos atributos. Note que os métodos de acesso
   // dinâmico funcionam como esperado mesmo com DynaBeans.
   System.out.println(PropertyUtils.getSimpleProperty(javaBeanTest,
     nomeStringProp));
   System.out.println(PropertyUtils.getSimpleProperty(javaBeanTest,
     nomeIntProp));
   System.out.println(PropertyUtils.getSimpleProperty(javaBeanTest,
     nomeListProp));
   System.out.println(PropertyUtils.getNestedProperty(javaBeanTest,
     shortPropEmAnotherJavaBean));
  } catch (IllegalAccessException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (InvocationTargetException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (NoSuchMethodException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }



Conclusão
Estes são, portanto, os componentes mais importante da biblioteca BeanUtils da apache commons. Esperem em breve por outros posts a respeito de bibliotecas co-irmãs!





















quinta-feira, 15 de abril de 2010

Flush-mode: Conversation

INTRODUCTION

Jboss Seam is a Java framework for web development which integrates technologies such as Asynchronous JavaScript and XML (AJAX), JavaServer Faces (JSF), Java Persistence (JPA), Enterprise Java Beans (EJB 3.0) and Business Process Management (BPM) into a unified full-stack solution, complete with sophisticated tooling. Its main feature is to easy the use of the technologies it integrates.

I thought about writing a post about jboss seam's main features and why I like it so much, but I won't do it for two reasons:
  1. There are already a lot of material on that topic (here, here, here, here, and here).
  2. The Jboss seam as we know it is coming to its end. The framework is so successful that it was, at least most part of it, incorporated by the JEE6 specification (mainly JSF2 and CDI). The future of the framework is at CDI's portable extensions, integrating the functionalities which were not standardized.



Nevertheless, I believe the actual version is still gonna be used for some time, so its worth to share a few clues related to specific points of the framework. This post in particular is about one of the main features of Jboss Seam: conversations.

CONVERSATION

The concept of conversation was not created by Seam, but it was the seam framework the first one to introduce it as a first class construct. In few words, a conversation is a context to hold application state, which scope is longer than a single request but shorter than the user's http session. A conversation represents a task the user can perform in the application and it is seam's default unit of work.

Under the hood, seam attaches the entity manager to the conversation context, so the entities remain persistent through the unit of work.  Also, it disables the automatic flush of the entity manager  (flush-mode: manual) so the changes don't get propagated to the database prematurely. That responsibility now stands with the developer, which issues a entity manager's flush at the end of the conversation.



The problem with that approach is the potential decrease of business method's re-usability as one method can be the last step of some conversation but not in another. 

AN EXAMPLE

Let's picture an human resources application which domain includes, obviously, employees and departments. It's acceptable to presume that such application includes a CRUD functionality to both models, being possible, in the latter one, to select a chief employee. The employee model includes a flag to determine whether she is a chief or not.

Accepting that a set of business rules are to be applied on a employee update (a conversation), we could come up with the following pseudo-method, responsible for the execution of such rules.

public void editEmployee(Employee employee){

peformRule1();

peformRule2();

peformRule3();

//Synchronize changes in the model with the database at the end of the conversation
this.entityManager.flush(); 


}


On the conversation responsible for editing departments, one of the steps would be exactly to update the chief employee (through the pseudo-method we just saw) and there's where the problem raises because this method executes an unexpected flush before the conversation is over.

public void editDepartamento(Department department, Employee employee){

peformRule1();

peformRule2();

employee.setChiefe(true);

//peforms an unwanted flush
editEmployee(employee); 

peformRule3();

//Synchronize changes in the model with the database at the end of the conversation
this.entityManager.flush(); 


}


For such a simple example, one could suggest some solutions such as force the employee's update to be the last step of the department's editing conversation, or to include a flag parameter to the employee editing method indicating whether it should perform a flush or not. None of these solutions is, nevertheless, adequate. What it's really needed is a way to ensure that the flush will be performed only at the end of a successful conversation, decoupling the database synchronization of the business logic.

//Refactored employee's editing method, receiving a boolean paramether inidicating whether the flush should be executed. Not the best solution!
public void editEmployee(Employee employee, Boolean peformFlush){

peformRule1();

peformRule2();

peformRule3();

if (peformFlush){
this.entityManager.flush(); 
//Synchronize changes in the model with the database at the end of the conversation
}

}

FLUSH MODE CONVERSATION

Even thought it doesn't exists built-in, seam provides mechanisms so we can get the same effect. The following solution is based on seam built-in events, specially one that's rose every time a conversation come to its end. We observe that event, performing a flush when it's needed.

@Name("endConverationObserver")
@Scope(ScopeType.CONVERSATION)
public class EndConverationObserver {

 @In
 private Boolean flushEntityManager;

 @In
 private EntityManager entityManager;

 @Observer(value = "org.jboss.seam.endConversation", create = true)
 public void DetermineflushEntityManager() {
  if (flushEntityManager) {
   this.entityManager.flush();
  }

 }

}

The weak point of such solution appears with the knowledge that not all ended conversations must perform a flush. Particularly, canceled conversations must not or the data will be synchronized with the database anyway. That's why a flag was included, so the component could ask the context whether it should perform the flush or not. It is the programmer's responsibility to feed the context with such boolean variable, whose default value would be true. It could be done, for example, in the actionListener of the cancel button.


@Name("editEmployeeController")
@Scope(ScopeType.CONVERSATION)
public class EditEmployeeController{

 @Out
 private Boolean flushEntityManager;

 @In
 private EntityManager entityManager;

 public String cancel() {
  this.flushEntityManager = false;
                return "editCancel"

 }

}

CONCLUSION

In this post we talked about seam's conversations and how they are usually implemented. An alternative approach was proposed, seeking to increase business methods reusability. Such approach uses bult-in mechanisms to decouple the database synchronization of the business methods.  

domingo, 11 de abril de 2010

flush-mode: Conversação

INTRODUÇÃO

Jboss Seam é um framework Java focado no desenvolvimento web que integra tecnologias como Ajax, Java Server Faces (JSF), Java Persistence (JPA), Enterprise Java Bean (EJB) e Business Process Management (BPM) em uma única solução apoiada por uma série de ferramentas sofisticadas. Sua principal característica é facilitar o uso das tecnologias que integra.

Pensei em fazer um post descrevendo as principais características deste framework e porque eu gosto tanto dele, mas não vou fazê-lo por 2 motivos:
  1. Já existe muito material assim por ai (aqui, aqui,aqui,aqui e aqui).
  2. O Jboss seam como existe hoje está com os dias contados. O framework foi tão bem sucedido que acabou sendo, em sua maioria, absorvido por especificações da plataforma JEE6 (em especial CDI e JSF2) O futuro do framework está em extensões portáveis para CDI integrando as funcionalidades não incorporadas a especificação.
No entanto, acredito que a versão atual ainda será usada por algum tempo, portanto, vale compartilhar algumas dicas referentes a pontos específicos do framework. A dica deste post é sobre uma das características mais marcantes do framework: conversações.

CONVERSAÇÃO

O conceito de conversação não foi inventado pelo jboss seam, mas foi este framework o primeiro a incorporá-lo como construção de primeira classe. Resumidamente pode-se dizer que uma conversação é um contexto onde o estado da aplicação pode ser armazenado, cujo escopo é maior que uma requisição mas inferior a sessão do usuário. Uma conversação representa uma tarefa que o usuário pode realizar na aplicação e é a unidade de trabalho padrão no jboss seam.

Por baixo dos panos, o seam inclui o entity manager no escopo de conversação, de forma que as entidades permaneçam persistentes durante toda a unidade de trabalho e desabilita o flush automático, (Flush-Mode: Manual) de forma que as alterações realizadas não sejam propagadas para o banco prematuramente. Esta responsabilidade é repassada ao desenvolvedor, que deve executar manualmente o flush no fim da conversação.



O problema com esta abordagem é que potencialmente pode reduzir a reusabilidade dos métodos de negócio, que em determinados momentos podem ser o último passo da conversação e em outros não.

UM EXEMPLO

Imaginemos por exemplo uma aplicação de RH cujo domínio inclui, obviamente, colaboradores e departamentos. É aceitável presumir que tal aplicação inclua, entre outras, uma funcionalidade de edição de colabores e outra para edição de departamentos, sendo possível, nesta última, apontar o colaborador responsável pelo departamento. A entidade que representa os colaboradores possui um marcador indicando determinado colaborador é um chefe ou não.

Se aceitarmos que uma série de regras de negócio deve ser executada durante a edição de um colaborador (uma conversação), podemos imaginar o seguinte pseudo-método, responsável pela execução destas regras.


public void editarColaborador(Colaborador colaborador){

executarRegra1();

executarRegra2();

executarRegra3();

//sincroniza as alterações na model com a base de dados no fim da conversação
this.entityManager.flush(); 


}


Na conversação referente à edição de departamentos, um dos passos seria justamente a edição do colaborador. O método negocial previamente definido deverá, portanto, ser invocado, e é ai que surge o problema porque este método executa o flush do entityManager o que é desejável apenas no fim da conversação da edição de departamentos.

public void editarDepartamento(Departamento departamento, Colaborador colaborador){

executarRegra1();

executarRegra2();

colaborador.setChefe(true);

//executa flush inadvertidamente
editarColaborador(colaborador); 

executarRegra3();

//sincroniza as alterações na model com a base de dados no fim da conversação
this.entityManager.flush(); 


}


Para este caso simples, algumas soluções podem ser propostas, como forçar que a edição do colaborador seja o último passo da conversação de edição de departamentos ou a inclusão de um parâmetro boleano no método de edição de colaborador indicando se o flush deve ou não acontecer. Nenhuma destas soluções, entretanto, é a adequada: o que precisamos mesmo é assegurar que o flush irá ocorrer apenas no fim de uma conversação bem sucedida, desacoplando a sincronização da lógica nos métodos negociais.


//Método de edição de colaborador refatorado para receber um parâmetro boleano indicando se o flush deve ou não ser executado. Não é a melhor solução!
public void editarColaborador(Colaborador colaborador, Boolean executarFlush){

executarRegra1();

executarRegra2();

executarRegra3();

if (executarFlush){
this.entityManager.flush(); //sincroniza as alterações na model com a base de dados
}

}

FLUSH-MODE: CONVERSATION

Apesar de não existir de forma built-in, o jboss seam disponibiliza alguns mecanismos que permitem obter efeito semelhante. A solução a seguir baseia-se no fato do seam levantar alguns eventos por padrão, entre eles um que indica o fim de uma conversação. A Idéia, portanto, consiste em disponibilizar um componente que observa este evento, fazendo o flush quando necessário.

@Name("endConverationObserver")
@Scope(ScopeType.CONVERSATION)
public class EndConverationObserver {

 @In
 private Boolean flushEntityManager;

 @In
 private EntityManager entityManager;

 @Observer(value = "org.jboss.seam.endConversation", create = true)
 public void DetermineflushEntityManager() {
  if (flushEntityManager) {
   this.entityManager.flush();
  }

 }

}


O ponto fraco desta solução emerge na percepção de que nem todo fim de conversação deve incluir sincronização com o banco. Em especial, as conversações canceladas não devem ter seus dados sincronizados! Para isso, foi incluída uma flag que indica se a sincronização deve mesmo ser efetuada, com o valor padrão igual a true. Se a sincronização não for desejada, o usuário deverá indicar isso setando o valor da variável para false. Isso pode ser feito por manipulação direta do contexto ou por meio de uma variável a ser ejetada.

@Name("editColaboradorController")
@Scope(ScopeType.CONVERSATION)
public class EditColaboradorController{

 @Out
 private Boolean flushEntityManager;

 @In
 private EntityManager entityManager;

 public String cancel() {
  this.flushEntityManager = false;
                return "editCancel"

 }

}

CONCLUSÃO

Neste post falamos sobre conversações no jboss seam e da maneira como geralmente são implementadas. Uma abordagem alternativa foi sugerida, buscando manter a reusabilidade dos métodos de negócio entre as conversações. Tal abordagem faz uso de recursos do próprio framework, como eventos bult-in e variáveis de contexto, para desacoplar a sincronização dos dados com o banco das regras de negócio.

sábado, 3 de abril de 2010

New Times for Java SE 7

In the Java world, working with dates – and time in general - has always been quite problematic. A series of design problems makes use of current API complex and bug prone. JSR-310 to the rescue! The new date and time API, still in development and to be integrated into version 7 of the Java SE platform, promises to finally end this headache that 11 out of 10 Java developers certainly have had to endure.

Problems with the Current API


Everybody agree that the Java’s date and time current API, exposed mainly through java.util.Date and java.util.Calendar classes, presents a series of inconveniences. Among them:
  • No classes representing concepts rather common as a date without time, time without date or even a period or interval. Because of that, the developer ends up using the API in a manner different from that for which it was designed.
  • The objects are not immutable, requiring external synchronization in a multi-thread environment.
  • Classes are limited to represent the date as an incremental number from an initial time (epoch). Besides being counter-intuitive, this approach makes difficult to manipulate the objects adequately.
These are exactly some of the problems that the JSR-310 proposes to solve.


JSR-310 Features


The main features of JSR-310 are:
  • Based on ISO-8601 - International Standard for representing dates and times.
  • Thread-safe - Its main objects are immutable.
  • More cohesion and readability-classes and their methods’ responsibilities are better defined and their names represent these responsibilities more clearly.
  • More Extensible - The API provides a set of extension points through which - mainly through the Strategy design pattern - You can customize and extend the behavior of the API, facilitating certain tasks of daily life.
  • Two different scales: machine (representing the passage of time using a single incremental number) and Human (representing the passage of time through the value of a number of fields, such as year, month, hour, etc.).

Concepts and main classes


The JSR-310 was built on some basic concepts, which reflects on the main classes of the API.

Instants

Instants represent a specific moment in a timeline with nanosecond precision. An example of an instant would be "June 3, 1983 the 12:03:00.0 UTC". Alternatively, a moment can be defined as a shift, in nanoseconds, from a default starting point - the epoch (which remains midnight on January 1, 1970).

There are several classes that represent a moment in the JSR-310 API : Instant, OffSetDateTime and ZonedDateTime.

Instant is one of the most basic API classes. It uses the machine scale. It should be seen as a substitute for java.util.Date. It has methods for comparison with other Instant and addition and subtraction of certain duration (remembering that the class is immutable)

Instant now= Clock.systemDefaultZone().instant();

Instant oneMoreMinute= now.plusSeconds(60); //returns a new Instant!

Boolean test = now.isAfter(oneMoreMinute); //false 




OffSetDateTime represents a day, time of day and a shift of the UTC (coordinated universal time). It uses, therefore, human scale.

OffsetDateTime today= Clock.systemDefaultZone().offsetDateTime();

OffsetDateTime birthday= OffsetDateTime.of(2009, MonthOfYear.NOVEMBER, 24,19,20,15,ZoneOffset.hours(-3));

System.out.println(today); //2009-11-24T19:20:15-03:00


ZonedDateTime is similar to OffSetDateTime, incorporating the ID of an area, such as America/New_York. This information is important as the offset from UTC may vary throughout the year according to the region (during daylight saving time, for example). When capturing these variations is important for business, a ZonedDateTime should be used.

TimeZone timeZone = TimeZone.of("Europe/Paris");
ZonedDateTime now= Clock.system(timeZone).zonedDateTime();
System.out.println(now); //current time in Paris time zone

Partial

Partials are representations of date/time witch are not sufficient to specify one point on a timeline. "December 25" or "12:15" are examples of partials.  Since they don’t determine a specific instant, it´s impossible to represent them as a nanosecond shift from epoch.

Some examples of partial in the API: MonthDay (representing a day in a month), Localtime (time with no date!) And LocalDate (Date without time!).

MonthDay easter= MonthDay.of(MonthOfYear.APRIL, 4);

LocalDate today= Clock.system(TimeZone.UTC).today();
Year year= today.toYear();
boolean leap= year.isLeap(); // is the current year leap?

LocalDateTime birthday= LocalDateTime.of(1983, MonthOfYear.JUNE, 3, 12, 00);

System.out.println(birthday);

LocalDateTime oneMonthAfter= birthday.plusMonths(1);

System.out.println(oneMonthAfter);

System.out.println(birthday.isBefore(oneMonthAfter)); //true 


Durations

Duration represents a certain amount of time with nanosecond precision. Very similar to the concept of Period, differs from it because it represents a certain amount of instants. In the API, the main class that represents duration is Duration.

long seconds= 60L;

Duration duration = Duration.seconds(seconds); // creates a one minute duration  

Instant instant1 = Clock.system(TimeZone.UTC).instant(); //current instant

Instant instant2 = instant1.plus(duration); //new instant crated adding a duration to another instant


Duration duration2 = Duration.durationBetween(instant1, instant2); // duration created from 2 instants

boolean equals = duration.equals(duration2);//true

System.out.println(equals);

Periods

As durations, periods represent a certain amount of time. Periods are represented, however, through a number of fields (year, month, time). In the API, periods are represented mainly by the class Period.

Period thePeriod = Period.years(8); // creates a eight years period 

LocalDate data = Clock.system(TimeZone.UTC).today();  

LocalDate eightYearsFromNow=  data.plus(thePeriod); //Adds the period to the current date.

System.out.println(eightYearsFromNow);




Customizing Behavior


As mentioned early, the JSR-310 offers some extension points, so that you can customize its behavior and implement some functionality in a more easy and straightforward way. Some of these extension points are:
  • Adjusters: Used to "adjust" dates, returning another date with a certain desired characteristic (a specific day or time, for example). The API provides some built-in Adjusters, like the one used to adjust a date to the last day of the month, for example.
  • Resolvers: Indicate how to handle an invalid date (if any operation resolve to Feb. 29 in a not leap year, for example). In this case the API also has default implementations, the most common being the one that resolves to the next valid date.
  • Matchers: Perform Boolean queries and dates and times, to know if the date has a specific characteristic (one day or time specific, for example). As in other cases, standards implementations are provided, to determine, for example, if the date belongs to a given year.

Conclusion


This post was about the main features of JSR 310, the new Java API for date and time that might be delivered together with the 7th version of the platform’s standard edition. This API provides significant improvements over the current API, as it was observed throughout the post.

References


http://wiki.java.net/bin/view/Projects/DateTimeEDR1 - JSR-310 Home at jana.net. Here you can find reference, user guide, java docs a reference implementation. Remember thught that the specificaion is still at development!


Revista Java Magazine yearVII 69 edition - Excellent article on the JSR-310.

terça-feira, 16 de março de 2010

Novos Tempos em Java SE 7

Em se tratando de Java, trabalhar com datas - e tempo de uma forma geral - sempre foi bastante problemático. Uma série de problemas de design faz com que o uso da API atual seja complexo e sujeito a bugs. JSR-310 to the rescue! A nova API de data e hora, ainda em desenvolvimento e a ser integrada na versão 7 da plataforma Java SE, promete finalmente por fim a esta dor de cabeça que 11 em cada 10 desenvolvedores Java certamente já tiveram de suportar.

Problemas com a API Atual

Todos concordam que a API atual de data e hora da plataforma Java, exposta principalmente através das classes java.util.Date e java.util.Calendar, apresenta uma série de inconveniências. Entre elas:
  • Ausência de classes que representem conceitos bastante comuns como data sem hora, hora sem data, ou mesmo um período ou intervalo. A ausência destas classes faz com que o desenvolvedor acabe usando a API de uma forma diferente daquela para a qual ela foi desenhada.
  • Os objetos não são imutáveis, requerendo sincronização externa em ambientes multi-thread.
  • As classes limitam-se a representar a data como um número incremental a partir de um momento inicial (epoch). Além de ser pouco intuitiva, esta abordagem dificulta a manipulação dos objetos de forma adequada.
Estes são alguns problemas que a JSR-310 se propõe a resolver.

Características da JSR-310

As principais características da JSR-310 são:
  • Baseada na ISO-8601 - padrão internacional para representação de datas e horas.
  • Thread-safe - Seus principais objetos são imutáveis.
  • Mais coesão e legibilidade- As classes e seus métodos têm responsabilidades melhor definidas e os nomes representam estas responsabilidades de maneira mais clara.
  • Mais Extensível - A API fornece uma série de "pontos de extensão" através dos quais - fazendo uso principalmente do desing patern Strategy - É possível customizar e estender o comportamento da API, facilitando certas tarefas do cotidiano.
  • Duas escalas distintas: Máquina (representa a passagem do tempo usando um único número incremental) e Humana (representa a passagem do tempo através do valor de um certo número de campos, tais como ano, mês, hora, etc.)

 Conceitos e principais classes

A JSR-310 foi construída em torno de alguns conceitos básicos, que refletem as principais classes da API. São eles:
Instantes
Instantes representam um momento específico na linha do tempo, com precisão de nanosegundos. Um exemplo de um instante seria "3 de Junho de 1983 as 12:03:00.0 UTC". Alternativamente, um instante pode ser definido como um deslocamento, em nanosegundos, de um momento inicial padrão - o epoch (que continua sendo meia noite de 1 de janeiro de 1970).

Existem diversas classes que representam um instante na API JSR-310: Instant, OffSetDateTime e ZonedDateTime.

Instant é uma das classes mais básicas da API. Usa a escala de máquina. Deve ser vista como a substituta da java.util.Date. Possui métodos de comparação com outros Instant e adição e subtração de certa duração (lembrando que a classe é imutável)

Instant agora = Clock.systemDefaultZone().instant();

Instant umMinutoAMais = agora.plusSeconds(60); //retorna um novo Instant!

Boolean test = agora.isAfter(umMinutoAMais); //false 

OffSetDateTime representa um dia, momento do dia e um deslocamento do UTC (coordinated universal time). Usa, portanto, escala humana.

OffsetDateTime hoje= Clock.systemDefaultZone().offsetDateTime();

OffsetDateTime aniversario= OffsetDateTime.of(2009, MonthOfYear.NOVEMBER, 24,19,20,15,ZoneOffset.hours(-3));

System.out.println(aniversario); //2009-11-24T19:20:15-03:00


ZonedDateTime é similar a OffSetDateTime, incorporando o ID de uma zona, como America/New_York. Esta informação é importante na medida em que o deslocamento do UTC pode variar ao longo do ano de acordo com a região (no horário de verão, por exemplo). Quando capturar estas variações é importante para o negócio, uma ZonedDateTime deve ser utilizada.

TimeZone timeZone = TimeZone.of("Europe/Paris");
ZonedDateTime agora= Clock.system(timeZone).zonedDateTime();
System.out.println(agora); //hora atual no time zone de paris

Parciais
Parciais são representações de data/hora insuficientes para especificar determinado momento na linha do tempo. 25 de Dezembro ou 12:15 são exemplos de parciais. Como não determinam um instante específico, não podem ser representados através de um deslocamento em nanosegundos do epoch. Usam, portanto, exclusivamente a escala humana.

Alguns exemplos de parciais na API: MonthDay (que representa um dia em um mês), LocalTime (hora sem data!)  e LocalDate (Data sem hora!)

MonthDay pascoa = MonthDay.of(MonthOfYear.APRIL, 4);

  LocalDate hoje = Clock.system(TimeZone.UTC).today();
  Year ano = hoje.toYear();
  boolean bissexto = ano.isLeap(); //Determina se o ano atual é bissexto.
  
  LocalDateTime aniversario = LocalDateTime.of(1983, MonthOfYear.JUNE, 3, 12, 00);
  
  System.out.println(aniversario);
  
  LocalDateTime umMesDepois = aniversario.plusMonths(1);
  
  System.out.println(umMesDepois);
  
  System.out.println(aniversario.isBefore(umMesDepois)); //true 

Durações
Uma duração representa certa quantidade de tempo, com precisão em nanosegundos. Bastante similar ao conceito de período, difere deste por representar uma quantidade determinada de instantes. Na API, a principal classe que representa uma duração é a Duration.

long segundos = 60L;
  
 Duration duration = Duration.seconds(segundos); //cria uma duração de 1 minuto
 
 Instant instante1 = Clock.system(TimeZone.UTC).instant(); //instante atual
 
 Instant instante2 = instante1.plus(duration); //Novo instante criado a parir do instante 1 + duração.
 
 Duration duration2 = Duration.durationBetween(instante1, instante2); // duração criada a partir de 2 instantes.
 
 boolean iguais = duration.equals(duration2);//true
 
 System.out.println(iguais);



Períodos
Assim como as durações, períodos representam certa quantidade de tempo. São representados, no entanto, através de um determinado número de campos (ano, mês, hora). Na API, períodos são representados principalmente pela classe Period.

Period thePeriod = Period.years(8); //cria um período de oito anos
  
  LocalDate data = Clock.system(TimeZone.UTC).today();  
  
  LocalDate daquiAOitoAnos =  data.plus(thePeriod); //adiciona o período a data atual.
  
  System.out.println(daquiAOitoAnos);


Customizando comportamento

Como foi mencionado, a JSR-310 oferece alguns pontos de extensão, de forma que é possível customizar seu comportamento e implementar algumas funcionalidade de forma mais fácil e direta. Alguns destes pontos de extensão:

  • Adjusters: Usados para "ajustar" datas, retornando outra data com certa característica desejada (um dia ou hora específicos, por exemplo). A API fornece alguns Adjusters built-in, para ajustar para o último dia do mês, por exemplo.
  • Resolvers: Indicam como tratar uma data inválida (se alguma operação resolver para o dia 29 de fevereiro de um ano que não seja bissexto, por exemplo). Neste caso a API também possui implementações padrão, sendo a mais comum a que resolve para a próxima data válida.
  • Matchers: Realizam consultas booleanas e datas e horas, para saber se a data possui determinada característica (um dia ou hora específicos, por exemplo). Como nos outros casos, implementações padrões são fornecidas, para determinar, por exemplo, se a data pertence a um determinado ano.

Conclusão

Este post discorreu sobre as principais características da JSR-310, a nova API Java para data e hora que deverá ser entregue juntamente com a versão 7 da plataforma SE. Esta API apresenta significantes melhorias em relação a API atual, como foi possível observar ao longo do post.

Referências


http://wiki.java.net/bin/view/Projects/DateTimeEDR1 - Casa da JSR-310 na java.net. Aqui é possível encontrar a referência, um user guide, java docs e uma implementação de referência. Vale salientar que a especificação ainda está em desenvolvimento!


Revista Java Magazine ano VII edição 69 - Excelente artigo sobre a JSR-310