GWT – JSON dates

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.

Anuncios

Apache CXF (JAX-RS) – Class java.util.Date can not be instantiated using a constructor with a single String argument

En Apache CXF JAX-RS existen los ParameterBeans que nos permiten crear una instancia de un objeto a partir de los parámetros enviados al servicio.

@POST
public String create(@FormParam("")Empleado empleado){
 try {
 DAO dao=new DAO();
 dao.ofy().put(empleado);
 Map<String, Object> response = new HashMap<String, Object>();
 Map<String, Object> body = new HashMap<String, Object>();
 body.put("status", 0);
 body.put("data", empleado);
 response.put("response", body);
 return json.writeValueAsString(response);
 } catch (Exception e) {
 log.error("", e);
 }
 return "{\"response\":{\"status\":-1, \"data\":\"Hubo un problema al guardar el Empleado\"}}";
}

En el ejemplo anterior se contruye un objeto Empleado a partir de los parámetros @FormParam enviados al servidor.

Los parámetros pueden ser de tipo String o cualquier tipo que tenga un constructor que reciba como parámetro una cadena o un método estático valueOf(String s). Adicionalmente CXF JAXRS puede utilizar el método fromString(String s) si existiera.


public class Empleado {

 Long id;
 String nombre;
 Date fechaNacimiento;

 public Empleado() {
 }

//getters y setters
}

Al utilizar la clase Empleado cómo parámetro, me arrojaba el siguiente error
ERROR [org.apache.cxf.jaxrs.utils.InjectionUtils] – Class java.util.Date can not be instantiated using a constructor with a single String argument
El mensaje del error es muy explícito. Pero entonces, ¿cómo le indicamos a Apache CXF que genere un objeto de tipo Date a partir de una cadena?
Bueno, pues tenemos que utilizar un ParameterHandler como el siguiente


/**
 * Converts ISO8601 parameters into date objects.
 *
 */
@Provider
public class ISO8601DateParamHandler implements ParameterHandler<Date> {

/**
 * Coerce an ISO8601 time string to a date object.
 *
 * @param s the string to parse.
 * @return the date object or null if the string cannot be parsed.
 */
 @Override
 public Date fromString(String s) {
 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
 try {
 return new Date(dateFormat.parse(s).getTime());
 } catch (ParseException e) {
 return null;
 }
 }
}

y configurarlo en nuestro archivo beans.xml

<jaxrs:server id="rest-api" address="/rest/gwt-audiencias">
 <jaxrs:providers>
 <bean class="com.mycompany.server.api.rest.ISO8601DateParamHandler" />
 </jaxrs:providers>
 <jaxrs:serviceBeans>
 <bean id="empleados"
 class="com.mycompany.server.api.rest.EmpleadosResource"></bean>
 </jaxrs:serviceBeans>
</jaxrs:server>

Fuentes:
http://cxf.547215.n5.nabble.com/ParameterHandler-not-invoked-for-Date-parameter-td2267734.html
http://cxf.apache.org/docs/jax-rs-basics.html#JAX-RSBasics-Parameterbeans
http://cxf.apache.org/docs/jaxrs-services-configuration.html

PostgreSQL – select sysdate from dual

Estoy probando la base de datos PostgreSQL. Uno de mis primeros dolores de cabeza fue como obtener la fecha y hora actual del servidor. En Oracle ejecutas el comando ‘select sysdate from dual’ pero en PostgreSQL marca el error:

ERROR:  relation “dual” does not exist

LINE 1: select sysdate from dual;

                            ^

********** Error **********

ERROR: relation “dual” does not exist

SQL state: 42P01

Character: 21

En PostgreSQL tienes que hacerlo de la siguiente manera:

select now();

o

select CURRENT_TIMESTAMP;

Fuentes:
http://www.postgresql.org/docs/7.4/static/functions-datetime.html 

BIRT – Formato de fecha desde un script


Tengo un encabezado estándar que uso en la mayoría de reportes, el cual he compartido a través de una librería. El detalle es que el título para cada reporte es diferente, así que en la plantilla coloqué etiquetas cuyo valor depende del parámetro que se les pase. Es común también que el título contenga el período que comprende el reporte. El formato de fecha que comunmente utilizamos es “dd/MM/yyyy” p. ej. 14/06/2011. Para dar este formato a las fechas -que recibo como párametros- utilizo el siguiente código en el evento “initialize” del reporte:

importPackage(Packages.java.text);
sdf = new SimpleDateFormat(“dd/MM/yyyy”);
params[“Titulo”]=”Reporte del “+sdf.format(params[“FechaInicio”])+” al “+sdf.format(params[“FechaFin”]);

Fuentes:
Eclipse Forums

GWT – Calcular fecha en el cliente

Update: Puedes utilizar la clase DateUtil de SmartGWT para calcular fechas del lado del cliente.

Para mostrar una alerta de acuerdo al tiempo que había pasado, necesitaba hacer un calculo simple; si la fecha actual es mayor -por treinta días- a mi fecha de referencia, entonces debía mostrarla.
Tenía 2 problemas, obtener la fecha actual y sumar 30 días a una fecha.
Para obtener la fecha actual

Date today=new Date();

solo que nos incluye la hora actual y a la hora de comparar se puede volver una pesadilla, para remover la información de la hora

Date time=new Date();
Date today=new Date(time.getYear(),time.getMonth(),time.getDate());

Utilizamos métodos obsoletos, pero bueno, funciona.

El mayor problema viene cuando intentamos hacer calculos con fechas, como sumar días.
Dada la definición de las fechas en GWT/javascript como

All dates are calculated in milliseconds from 01 January, 1970 00:00:00
Universal Time (UTC) with a day containing 86,400,000 milliseconds.

w3schools
Podríamos hacerlo mediante la siguiente función

public Date addDays(Date date,int days){
return new Date(date.getTime()+days*1000*60*60*24);
}

Genial! lamentablemente no funciona, a mi no me arrojó ningún error, simplemente los calculos estaban mal. No se cual sea el problema, supongo que se debe a que el método Date.getTime() regresa un tipo de dato “long” y de acuerdo a la guía de GWT, este tipo de dato no se puede pasar de Java/GWT a javascript ni cómo parámetro ni como valor de retorno.
La única forma que encontré de hacer este cálculo fue mediante JSNI pasando los valores de tipo long como double, como lo hace la clase DateUtil de Gwt-Ext.

public static class DateUtils{

		protected DateUtils() {
		}

		public static Date createDate(double time){
			return new Date((long) time);
		}
		public static double getTime(Date date){
			return date.getTime();
		}

		public static native Date currentDate()/*-{
			var time=new $wnd.Date();
			var today=new $wnd.Date(time.getFullYear(),time.getMonth(),time.getDate(),0,0,0,0);
			return @package.DateUtils::createDate(D)(today.getTime());
		}-*/;

		public static native Date addDays(Date date,int days)/*-{
			var millis=@package.DateUtils::getTime(Ljava/util/Date;)(date);
			var jsDate= new $wnd.Date(millis+days*1000*60*60*24);
			return @package.DateUtils::createDate(D)(jsDate.getTime());
		}-*/;

	}

Fuentes:
Coding Basics – JavaScript Native Interface (JSNI)
GwtExt DateUtil source code
w3schools – JavaScript Date
SmartGwt Forum
blog.gerardin.info – GWT and Javascript Date Hell

GWT – Darle formato a una fecha


En Java, cuando quiero darle formato a una fecha o “parsear” una cadena para convertirla en un objeto Date, utilizo la clase SimpleDateFormat de la siguiente forma

SimpleDateFormat fmtDate=new SimpleDateFormat(“dd/MM/yyyy”);
String fecha=fmtDate.format(new Date());

Esto lo podemos hacer sin problemas en el servidor 😉 pero, que pasa cuando lo intentamos en el Cliente. Bueno, pues tenemos que utilizar la clase DateTimeFormat de la siguiente manera

DateTimeFormat fmtDate=DateTimeFormat.getFormat(“dd/MM/yyyy”);
String fecha=fmtDate.format(new Date());

SmartGwt – Obtener la fecha actual (sin hora)

En una aplicacion necesitaba establecer el valor por default de unos calendarios, con la fecha actual. Lo primero que hice fue

DateItem dtiFechaRecepcionInicio = new DateItem();
dtiFechaRecepcionInicio.setValue(new Date());

Y si muestra la fecha actual, pero a la hora de leer el valor y enviarlo al servidor para realizar una consulta me di cuenta que su valor incluia la hora (con hora me refiero a las horas, minutos, segundos y milisegundos). Esto me causo problemas en mi consulta.
Lo que intente despues fue establecer las horas, minutos, segundos y milisegundos en ‘0’ (cero) mediante los metodos setHours, setMinutes, setSeconds y ….. pues no hay setMilliseconds. De todos modos lo intente, pero igual me causo problemas a la hora de comparar la fecha con otras almacenadas en el servidor.
Finalmente lo que hice fue lo siguiente:

Date currentDateTime=new Date();
        Date currentDate=new Date(currentDateTime.getYear(),currentDateTime.getMonth(),currentDateTime.getDate());
        return currentDate;