sexta-feira, 18 de dezembro de 2009

Serializador Java para JSON - Parte II

Na Parte I do post sobre JSON, postei o código da biblioteca. Nesta parte dois, está um exemplo de uso, que é formado por uma classe principal (TesteJson) e pelas classes Person e PhoneNumber para ilustrar o uso de objetos para a escrita do código JSON.

Código da classe PhoneNumber

public class PhoneNumber {
    private int code;
    private String number;
    
    public PhoneNumber() {
    }

    public PhoneNumber(int code, String number) {
        this.code = code;
        this.number = number;
    }
    //Métodos GET e SET..... 
}



Código da classe Person

import java.util.Date;
import java.util.List;

public class Person {
    private String firstName;
    private String lastname;
    private int idade;
    private boolean casado;
    private Boolean solteiro;
    private Long altura;
    private Integer numero;
    private PhoneNumber phone;
    private PhoneNumber fax;
    private Date data;
    private List phones;
    private PhoneNumber[] arrayPhones;

    public Person() {}

    public Person(String fn, String ln) {
        this.firstName = fn;
        this.lastname = ln;
    }

    // Métodos GET e SET........
}




Código da classe TesteJson

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import json.serializer.JSONSerializer;

public class TesteJson {
    public static void main(String[] args) {
        Person joe = new Person("Joe", "Wayne");
        PhoneNumber phoneJoe = new PhoneNumber(321, "5565-987");
        PhoneNumber fax      = new PhoneNumber(123, "9999-999");
        PhoneNumber[] arrayPhones = new PhoneNumber[2];
        arrayPhones[0] = phoneJoe;
        arrayPhones[0] = fax;
        List phones = new ArrayList();
        phones.add(phoneJoe);
        phones.add(fax);

        joe.setPhone(phoneJoe);
        joe.setFax(fax);
        joe.setData(Calendar.getInstance().getTime());
        joe.setIdade(12);
        joe.setAltura(new Long(120));
        joe.setArrayPhones(arrayPhones);
        joe.setPhones(phones);
        joe.setAltura(new Long(120));
        joe.setCasado(true);
        joe.setSolteiro(new Boolean(false));
        joe.setNumero(new Integer(53));

        Person moe = new Person("Bart", "Simpson");
        PhoneNumber phone = new PhoneNumber(321, "5565-987");
        moe.setPhone(phone);
        moe.setFax(new PhoneNumber(321, "9999-999"));
        moe.setData(Calendar.getInstance().getTime());
        
        List collection = new ArrayList();
        collection.add(joe);
        collection.add(moe);

        JSONSerializer serial = new JSONSerializer();
        String strJoe = serial.serialize(joe);
        System.out.println(strJoe);
        
        serial = new JSONSerializer();
        strJoe = serial.serialize(collection);
        System.out.println(strJoe);
    }
} 


Serializador Java para JSON - Parte I

JSON é uma forma de transferência de dados que está sendo utilizado bastante atualmente. Possui um formato bastante que deixa o conjunto de dados bastante enxuto.

Desenvolvi estas classes baseadas na biblioteca FlexJson: http://flexjson.sourceforge.net/ . Fiz algumas alterações que deixou a biblioteca bem menor. Mas, minha motivação principal foi que eu pudesse utilizar a biblioteca  na versão 1.4 do Java. Ao todo, a biblioteca ficou com apenas quatro classes: ChainedIterator, ChainedSet, JSONSerializer, ObjectVisitor. Vou colocar o código de todas elas, e também um exemplo de uso.

Código da classse ChainedIterator

import java.util.Iterator;
import java.util.Iterator;
import java.util.Set;

public class ChainedIterator implements Iterator {
    Iterator[] iterators;
    int current = 0;

    public ChainedIterator(Set sets) {
     Object[] arraySets = sets.toArray(); 
        iterators = new Iterator[sets.size()];
        for( int i = 0; i < sets.size(); i++ ) {
            iterators[i] = ((Set)arraySets[i]).iterator();
        }
    }

    public boolean hasNext() {
        if( iterators[current].hasNext() ) {
            return true;
        } else {
            current++;
            return current < iterators.length && iterators[current].hasNext();
        }
    }

    public Object next() {
        return iterators[current].next();
    }

    public void remove() {
        iterators[current].remove();
    }
}

Código da classe ChainedSet
import java.util.Set;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Collection;
import java.util.TreeSet;

public class ChainedSet implements Set {
    Set parent;
    Set child;

    public ChainedSet(Set parent) {
        this.parent = parent;
        this.child = new HashSet();
    }

    public int size() {
        return this.child.size() + parent.size();
    }

    public boolean isEmpty() {
        return this.child.isEmpty() && parent.isEmpty();
    }

    public boolean contains(Object o) {
        return child.contains(o) || parent.contains(o);
    }

    public Iterator iterator() {
     Set sets = new TreeSet();
     sets.add(child);
     sets.add(parent);
        return new ChainedIterator(sets);
    }

    public Object[] toArray() {
        Object[] carr = child.toArray();
        Object[] parr = parent.toArray();
        Object[] combined = new Object[ carr.length + parr.length ];
        System.arraycopy( carr, 0, combined, 0, carr.length );
        System.arraycopy( parr, 0, combined, carr.length, parr.length );
        return combined;
    }

    public Object[] toArray(Object[] a) {
        throw new IllegalStateException( "Not implemeneted" );
    }

    public boolean add(Object o) {
        return child.add( o );
    }

    public boolean remove(Object o) {
        return child.remove( o );
    }

    public boolean containsAll(Collection c) {
        return child.containsAll(c) || parent.containsAll(c); 
    }

    public boolean addAll(Collection c) {
        return child.addAll( c );
    }

    public boolean retainAll(Collection c) {
        return child.retainAll( c );
    }

    public boolean removeAll(Collection c) {
        return child.removeAll( c );
    }

    public void clear() {
        child.clear();
    }

    public Set getParent() {
        return parent;
    }
}
Código da classe JSONSerializer
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class JSONSerializer {

    public final static char[] HEX = "0123456789ABCDEF".toCharArray();

    List pathExpressions = new ArrayList();
    Map transformations = new HashMap();

    public JSONSerializer() {
    }

    public String serialize( String rootName, Object target ) {
        return new ObjectVisitor().visit( rootName, target );
    }

    public String serialize( Object target ) {
        return new ObjectVisitor().visit( target );
    }

    public String prettyPrint( Object target ) {
        return new ObjectVisitor( true ).visit( target );
    }

    public String prettyPrint( String rootName, Object target ) {
        return new ObjectVisitor( true ).visit( rootName, target );
    }
}

Código da classe ObjectVisitor
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;

public class ObjectVisitor {
    protected StringBuffer builder;
    protected boolean prettyPrint = false;
    private int amount = 0;
    private boolean insideArray = false;

    protected ObjectVisitor() {
        builder = new StringBuffer();
    }

    public ObjectVisitor(boolean prettyPrint) {
        this();
        this.prettyPrint = prettyPrint;
    }

    public String visit( Object target ) {
        json( target );
        return builder.toString();
    }

    public String visit( String rootName, Object target ) {
        beginObject();
        string(rootName);
        add(':');
        json( target );
        endObject();
        return builder.toString();
    }

    private void numberToString(Number n) {
  if (n != null && testValidity(n)) {
   String s = n.toString();
   if (s.indexOf('.') > 0 && s.indexOf('e') < 0 && s.indexOf('E') < 0) {
    while (s.endsWith("0")) {
     s = s.substring(0, s.length() - 1);
    }
    if (s.endsWith(".")) {
     s = s.substring(0, s.length() - 1);
    }
   }
   add(s);
  }else{
            add("0");
  }
 }
    
    private boolean testValidity(Object o) {
        if (o != null) {
            if (o instanceof Double) {
                if (((Double)o).isInfinite() || ((Double)o).isNaN()) {
                    return false;
                }
            } else if (o instanceof Float) {
                if (((Float)o).isInfinite() || ((Float)o).isNaN()) {
                    return false;
                }
            }
        }
        return true;
    }
    
    
    private void json(Object object) {
        if (object == null) add("null");
        else if (object instanceof Class)
            string( ((Class)object).getName() );
        else if (object instanceof Boolean)
            bool( ((Boolean) object) );
        else if (object instanceof String)
            string(object);
        else if (object instanceof Character)
            string(object);
        else if (object instanceof Number)
            numberToString((Number) object);
        else if (object instanceof Map)
            map( (Map)object);
        else if (object.getClass().isArray())
            array( object );
        else if( object instanceof Date)             
            date( (Date)object );
        else if (object instanceof Collection)
            array(((Collection) object).iterator() );            
        else
            bean( object );
    }

    private void map(Map map) {
        beginObject();
        Iterator it = map.keySet().iterator();
        boolean firstField = true;
        while (it.hasNext()) {
            Object key = it.next();
            int len = builder.length();
            add( key, map.get(key), firstField );
            if( len < builder.length() ) {
                firstField = false;
            }
        }
        endObject();
    }

    private void array(Iterator it) {
        beginArray();
        while (it.hasNext()) {
            if( prettyPrint ) {
                addNewline();
            }
            addArrayElement( it.next(), it.hasNext() );
        }
        endArray();
    }

    private void array(Object object) {
        beginArray();
        int length = Array.getLength(object);
        for (int i = 0; i < length; ++i) {
            if( prettyPrint ) {
                addNewline();
            }
            addArrayElement( Array.get(object, i), i < length - 1 );
        }
        endArray();
    }

    private void addArrayElement(Object object, boolean isLast ) {
        int len = builder.length();
        json( object );
        if( len < builder.length() ) { // make sure we at least added an element.
            if ( isLast ) add(',');
        }
    }

    private void bool(Boolean b) {
        add( b.booleanValue() ? "true" : "false" );
    }

    private void string(Object obj) {
        add('"');
        CharacterIterator it = new StringCharacterIterator(obj.toString());
        for (char c = it.first(); c != CharacterIterator.DONE; c = it.next()) {
            if (c == '"') add("\\\"");
            else if (c == '\\') add("\\\\");
            else if (c == '\b') add("\\b");
            else if (c == '\f') add("\\f");
            else if (c == '\n') add("\\n");
            else if (c == '\r') add("\\r");
            else if (c == '\t') add("\\t");
            else if (Character.isISOControl(c)) {
                unicode(c);
            } else {
                add(c);
            }
        }            
        add('"');
    }

    private void date(Date date) {
        builder.append( date.getTime());
    }

    private ChainedSet visits = new ChainedSet( Collections.EMPTY_SET );

    protected void bean(Object bean) {
        if( !visits.contains( bean ) ) {
            visits = new ChainedSet( visits );
            visits.add( bean );
            beginObject();
            try {
                Class klass = bean.getClass();

                Method[] methods = klass.getMethods();
                boolean firstField = true;
                for (int i = 0; i < methods.length; i += 1) {
                    Method method = methods[i];
                    if (Modifier.isPublic(method.getModifiers())) {
                        String name = method.getName();
                        String key = "";
                        boolean invoke = false;
                        if (name.startsWith("get")) {
                         invoke = true;
                            key = name.substring(3);
                        } else if (name.startsWith("is")) {
                            key = name.substring(2);
                            invoke = true;
                        }
                        if (key.length() > 0){
                         key = String.valueOf(key.charAt(0)).toLowerCase() + key.substring(1);
                        }
                        
                        if (invoke) {
                            Object value = method.invoke(bean, (Object[])null);
                            
                            if( !visits.contains( value ) ) {
                             add(key, value, firstField);
                             firstField = false;
                            }
                        }
                    }
                }
            } catch( Exception e ) {
             
            }
            endObject();
            visits = (ChainedSet) visits.getParent();
        }
    }
    
    protected boolean addComma(boolean firstField) {
        if ( !firstField ) {
            add(',');
        } else {
            firstField = false;
        }
        return firstField;
    }

    protected void beginObject() {
        if( prettyPrint ) {
            if( insideArray ) {
                indent( amount );
            }
            amount += 4;
        }
        add( '{' );
    }

    protected void endObject() {
        if( prettyPrint ) {
            addNewline();
            amount -= 4;
            indent( amount );
        }
        add( '}' );
    }

    private void beginArray() {
        if( prettyPrint ) {
            amount += 4;
            insideArray = true;
        }
        add('[');
    }

    private void endArray() {
        if( prettyPrint ) {
            addNewline();
            amount -= 4;
            insideArray = false;
            indent( amount );
        }
        add(']');
    }

    protected void add( char c ) {
        builder.append( c );
    }

    private void indent(int amount) {
        for( int i = 0; i < amount; i++ ) {
            builder.append( " " );
        }
    }

    private void addNewline() {
        builder.append("\n");
    }

    protected void add( Object value ) {
        builder.append( value );
    }

    protected void add(Object key, Object value, boolean prependComma) {
        int start = builder.length();
        addComma( prependComma );
        addAttribute( key );

        int len = builder.length();
        json( value );
        if( len == builder.length() ) {
            builder.delete( start, len ); // erase the attribute key we didn't output anything.
        }
    }

    private void addAttribute(Object key) {
        if( prettyPrint ) {
            addNewline();
            indent( amount );
        }
        builder.append("\"");
        builder.append( key );
        builder.append( "\"" );
        builder.append( ":" );
        if( prettyPrint ) {
            builder.append(" ");
        }
    }

    private void unicode(char c) {
        add("\\u");
        int n = c;
        for (int i = 0; i < 4; ++i) {
            int digit = (n & 0xf000) >> 12;
            add(JSONSerializer.HEX[digit]);
            n <<= 4;
        }
    }
}


quinta-feira, 17 de dezembro de 2009

Lookup de um EJB

A seguinte classe é um exemplo básico de como fazer um lookup em um EJB.

O servidor utilizado foi o JBoss, versão 4.0.

É importante que o EJB possua uma interface remota para que o lookup funcione.

import javax.naming.InitialContext;

import br.com.ebiz.funasawf.entity.Usuario;
import br.com.ebiz.funasawf.service.cadastro.UsuarioLocal;

public class LookupEJB {
  public static void main(String[] args) {
    Hashtable environment = new Hashtable();
    environment.put("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");
    environment.put("java.naming.factory.url.pkgs","org.jboss.naming:org.jnp.interfaces");
    environment.put("java.naming.provider.url", "localhost:1099");
    // remote machine IP
    InitialContext context;
    try {
      context = new InitialContext(environment);
      UsuarioLocal pl = (UsuarioLocal) context.lookup("funasawf/UsuarioWFBean/remote");
      Usuario user = pl.findById(39L);
      System.out.println(user.getNmeLogin());
    } catch (Exception e) {}
  }
}

Esse tipo de código é bastante útil para realizar testes na aplicação.

Para poder realizar os testes, você vai precisar das bibliotecas do JBoss: server e client. Além disso, você vai precisar referenciar as classes da sua aplicação, EntityBeans e SessionBeans, como no exemplo, Usuario e UsuarioLocal.