Para organizar el código del cliente utilizo Overlay Types.

En un método intenté regresar un valor de tipo Integer, lo cuál me arrojaba una excepción de tipo IllegalArgumentException.

    public class Sala extends JavaScriptObject{
        public native final Integer getId()/*-{
            return this.id;
        }-*/; 

        public final String getNombre(){
            return JSOHelper.getAttribute(this, "nombre");
        }
        protected Sala() {
        } 

    }

esto es debido a que, en Javascript, el atributo ‘this.id’ es de tipo number y JSNI no puede hacer la conversión automáticamente.
Debemos realizar la conversión de la siguiente manera

    public native final Integer getId()/*-{
        return this.id ? @java.lang.Integer::valueOf(I)(this.id) : null;
    }-*/;

Fuentes:
https://code.google.com/p/google-web-toolkit/issues/detail?id=2972#c6
https://developers.google.com/web-toolkit/doc/latest/DevGuideCodingBasicsJSNI#methods-fields
http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/types.html#wp16432

GWT – JSON dates

marzo 11, 2013

JSON no tiene un tipo de dato Date, así que cuando transfieres fechas mediante JSON debes convenir un formato de fecha -por ejemplo, yyyy-MM-dd’T’hh:mm:ss.SZ- Un ejemplo de fecha en este formato sería “2013-03-08T16:23:35.000+0000”.

Para facilitar un poco las cosas, decidí utilizar un Overlay Type para la representación de mi objeto y acceder a sus propiedades mediante getter’s y setter’s. Estos métodos realizan la conversión de cadena a fecha, y viceversa, con la ayuda de la clase DateTimeFormat.

    public class Audiencia extends JavaScriptObject {</p><pre><code>    private final static DateTimeFormat dateTimeFormat = DateTimeFormat.getFormat("yyyy-MM-dd'T'hh:mm:ss.SZ");

    public final native int getId()/*-{
        return this.id;
    }-*/;

    public final Date getInicio(){
        return dateTimeFormat.parseStrict(getInicioNative());
    };

    private final native String getInicioNative()/*-{
        return this.inicio;
    }-*/;

    public final Date getFin(){
        return dateTimeFormat.parseStrict(getFinNative());
    };

    private final native String getFinNative()/*-{
        return this.fin;
    }-*/;

    protected Audiencia() {
    }

    public static void getAudiencias(String idSala,
            final AsyncCallback&lt;Audiencia[]&gt; callback) {
        try {
            String queryParams = "?sala="+URL.encodeQueryString(idSala);
            RequestBuilder rb = new RequestBuilder(RequestBuilder.GET,
                    Consts.REST_AUDIENCIAS + queryParams);
            rb.sendRequest(null, new RequestCallback() {

                @Override
                public void onResponseReceived(Request request,
                        Response response) {
                    if(response.getStatusCode() == 200){
                        JavaScriptObject jso = JSON.decode(response.getText());
                        DSResponse ds = new DSResponse(JSOHelper.getAttributeAsJavaScriptObject(jso, "response"));
                        if(ds.getStatus() == 0){
                            Record[] records = ds.getData();
                            Audiencia[] audiencias = new Audiencia[records.length];
                            for(int i=0;i&lt;records.length;i++){
                                audiencias[i] = (Audiencia) records[i].getJsObj();
                            }
                            callback.onSuccess(audiencias);
                        }else{
                            callback.onFailure(new Exception(ds.getAttributeAsString("data")));
                        }
                    }else{
                        callback.onFailure(new Exception(response.getStatusText()));
                    }
                }

                @Override
                public void onError(Request request, Throwable exception) {
                    callback.onFailure(exception);
                }
            });
        } catch (Exception e) {
            callback.onFailure(e);
        }
    }

}
</code></pre><p>

Esto es necesario porque el método JSON.decode) crea el objeto Javascript con propiedades (inicio y fin) de tipo String.

Cuando intentaba hacer un cálculo sencillo para colocar una ventana en determinada posición, me aparecía el siguiente error

com.google.gwt.dev.shell.HostedModeException: invoke arguments: JS value of type string, expected int

el problema era la forma en que establecí el tamaño de la ventana, utilicé el método setSize -que recibe como parámetros cadenas- e intenté invocar el método getWidth antes de haber pintado/mostrado el control en pantalla.

@Override
public void onModuleLoad() {
    Window win = new Window();
    win.setSize("320", "180");
    SC.say("Window width: "+win.getWidth()); // throws Exception
}

Después de mostrar el control si puedes utilizar el método getWidth()

@Override
public void onModuleLoad() {
    Window win = new Window();
    win.setSize("320", "180");
    win.show();
    SC.say("Window width: "+win.getWidth()); // "Window width: 320"
}

Si necesitas el valor del width antes de mostrar el control -como era mi caso- tienes que utilizar el método getWidthAsString() y convertir la cadena a Integer

@Override
public void onModuleLoad() {
    Window win = new Window();
    win.setSize("320", "180");
    SC.say("Window width: "+Integer.parseInt(win.getWidthAsString()));
}

Fuentes:
SmartClient Forums

Para modificar la consulta de un DataSet puedes utilizar la sección “Property Binding”

en mi caso necesitaba reemplazar en la conulta el valor de un parámetro.

Para reemplazar una cadena con otra lo puedes hacer en el “Expression Builder” de la siguiente manera



var q=new Packages.java.lang.String("SELECT COUNT(*) AS TOTAL \
FROM @OFICINA.EMPLEADOS A, @OFICINA.PUESTOS R, \
@OFICINA.SALARIOS D, @OFICINA.DEPTOS O \
WHERE A.NID_ACO_EXP= R.NID_ACO \
R.NID_DMD=D.NID_DMD AND R.NORDEN=O.NID_ORDEN \
AND TRUNC(R.FECHA) BETWEEN :INICIO AND :FIN");
q.replaceAll("@OFICINA",params["OFICINA"].value);

el código es javascript, pero podemos utilizar clases Java también. En este caso utilizamos la clase String de Java en vez de Javascript, porque el método de javascript no reemplaza todas las coincidencias.

Fuentes:
birt exchange

Un tipo de propiedad que encontramos comunmente en nuestros objetos es el tipo Boolean. Puede ser para describir si un registro esta activo o no, o para marcar una tarea como realizada, etc. En una base de datos no es común encontrar este tipo de dato para una columna. Normalmente lo representamos mediante un Number(‘0’ o ‘1’) o un Char (‘S’ o ‘N’). En nuestro caso utilizamos el Char.

Al utilizar Datanucleus con JDO para mapear la siguiente clase

@PersistenceCapable(table="TC_EMPLEADOS")
public class Empleado {
@PrimaryKey
@Persistent(column="NID")
Integer id;
@Persistent(column="SNOMBRE")
String nombre;
@Persistent(column="BACTIVO")
Boolean activo;
public Empleado() {
}

}

me arrojaba un error parecido al siguiente:

NucleusDatastoreException: Fail to convert to internal representation

El problema es que, por default, Datanucleus trata de mapear la propiedad “activo” a un valor númerico (‘0’ o ‘1’). Para mapear la propiedad a una cadena podemos hacer lo siguiente:

@PersistenceCapable(table="TC_EMPLEADOS")
public class Empleado {

@PrimaryKey
@Persistent(column="NID")
Integer id;

@Persistent(column="SNOMBRE")
String nombre;

@Persistent(column="BACTIVO")
String activo;

public Empleado() {
}

public Boolean getActiv0() {
   return "S".equals(activo);
}

public void setActivo(Boolean activo) {
   this.activo = activo?"S":"N";
}

}

Notesé que utilizamos el tipo String para la propiedad y Boolean para los métodos de acceso a la propiedad.

Fuentes:

http://turbomanage.wordpress.com/2009/12/04/persisting-enums-with-appengine-datastore/

Para formatear un número a dos dígitos, de tal forma que “1” lo imprima como “01”, puedes utilizar el método String.Format() de la siguiente manera:

int mes=1;
String.format(“%02d”,mes); //regresa la cadena ’01’

Fuentes:
http://www.coderanch.com/t/422920/java/java/Display-integer-always-two-digit 

Para no almacenar las contraseñas de los usuarios, puedes guardar el hash y compararlo en el proceso de inicio de sesión. Existen varios algoritmos que te permiten obtener un hash, aquí mostraré cómo utilizar el SHA-256 en java.

String password="secret";
MessageDigest sha256=MessageDigest.getInstance("SHA-256");
sha256.update(password.getBytes("UTF-8"));
byte[] digest = sha256.digest();
StringBuffer sb=new StringBuffer();
for(int i=0;i&lt;digest.length;i++){
    sb.append(String.format("%02x", digest[i]));
}
String hash=sb.toString(); //2bb80d5...527a25b

En internet hay una función que utiliza el método Integer.toHexString pero ésta no imprime el prefijo 0 (cero) en los número menores a 16, es decir, “0d” lo imprime como “d”; lo que causa una diferencia si lo comparas con el hash generado en la línea de comandos de Linux.

Para generar la cadena en la línea de comandos de linux, ejecuta el siguiente comando

echo -n "secret_password" | sha256sum

es importante el parámetro -n en el comando echo para que no agregué un carácter de salto de línea

Fuentes:
http://stackoverflow.com/questions/3021970/which-sha-256-is-correct-the-java-sha-256-digest-or-the-linux-commandline-tool