Para acceder a los objetos de una colección en una plantilla de Handlebars tienes que pasar dichos objetos como un parámetro a la función template. Si utilizas Backbone y tu colección de objetos es una colección de modelos, puedes utilizar la función toJSON para convertirlos en objetos javascript y que puedan ser interpretados por Handlebars.

Supongamos que tenemos los siguientes objetos (modelos)

app.models.Equipo = Backbone.Model.extend({

    initialize: function () {

    },

    sync: function (method, model, options) {
    if (method === 'read') {
        app.adapters.equipos.findById(parseInt(this.id)).done(function (data) {
            options.success(data)
        })
    }
    }
})

app.models.EquipoCollection = Backbone.Collection.extend({

    model: app.models.Equipo,

    sync: function (method, model, options) {
    if (method === 'read') {
        app.adapters.equipos.findAll().done(function(data){
            options.success(data)
        })
    }
    }
})

y nuestra plantilla es la siguiente

    <div class="row">
        {{#each equipos}}
        <div class="col-6">
            <a href="equipos/#{{name}}" class="thumbnail text-center">
                <img src="{{logoUrl}}"/>
            </a>
        </div>
        {{/each}}
    </div>

Entonces para pasar nuestros objetos a la plantilla, lo haríamos de la siguiente manera

app.views.EquiposListView = Backbone.View.extend({
    initialize: function(){
        this.equipos = new app.models.EquipoCollection()
        this.equipos.on('reset', this.render, this)
        this.equipos.fetch({reset: true})
    },

    render: function(){
        this.$el.html(this.template({equipos: this.equipos.toJSON()}))
        return this
    }

})

Notesé el uso de la función toJSON

Fuentes:
http://stackoverflow.com/questions/12439471/rendering-handlebars-template-with-backbone
http://stackoverflow.com/questions/14170298/how-to-access-backbone-model-properties-in-a-handlebar-template

Anuncios

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.

Para obtener el tipo de dato de las propiedades de un objeto podemos utilizar la reflexión.

Por ejemplo si tenemos las siguientes clases

public class Libro{
String isbn;
String titulo;
Autor autor;
}
public class Autor{
String id;
String nombre;
Date fechaNacimiento;
}

Un método para obtener el tipo de dato de una propiedad, incluso propiedades anidadas, sería el siguiente

private Class<?> getPropertyType(Class<?> clazz,String property){
 try{
 LinkedList<String> properties=new LinkedList<String>();
 properties.addAll(Arrays.asList(property.split("\\.")));
 Field field = null;
 while(!properties.isEmpty()){
 field = FieldUtils.getField(clazz,properties.removeFirst(),true);
 clazz=field.getType();
 }
 return field.getType();
 }catch(Exception e){
 throw new RuntimeException(e);
 }
}

Lo invocaríamos de la siguiente manera

Class<?> type=getPropertyType(Libro.class,"autor.fechaNacimiento");
System.out.println(type.toString()); //imprime java.util.Date

Notesé el uso de la clase FieldUtils de la librería Apache Commons Lang, cuyo método getField busca el campo recursivamente en la jerarquía de las clase y sus interfaces. Para agregar la librería a nuestro proyecto hay que agregar la siguiente dependencia


<dependency>
 <groupId>org.apache.commons</groupId>
 <artifactId>commons-lang3</artifactId>
 <version>3.1</version>
 </dependency>

Para listar todas las propiedades de un objeto recursivamente podemos utilizar como ejemplo el código de la clase FieldUtils.

Con la librería Jackson podemos obtener un esquema JSON de cualquier objeto. El detalle es que los tipos de datos que obtendríamos serían sólo los permitidos en JSON (string, number, boolean, object, array, null).

ObjectMapper mapper=new ObjectMapper();
System.out.println(mapper.generateJsonSchema(Libro.class));

Fuentes:
http://stackoverflow.com/questions/11125409/find-the-field-type-using-jackson-json
http://stackoverflow.com/questions/3567372/access-to-private-inherited-fields-via-reflection-in-java
http://wiki.fasterxml.com/JacksonJavaDocs
http://jackson.codehaus.org/1.8.8/javadoc/org/codehaus/jackson/map/ObjectMapper.html#generateJsonSchema(java.lang.Class)
http://wiki.fasterxml.com/JacksonTreeModel

En orientación a objetos la herencia es, después de la agregación o composición, el mecanismo más utilizado para alcanzar algunos de los objetivos más preciados en el desarrollo de software como lo son la reutilización y la extensibilidad. A través de ella los diseñadores pueden crear nuevas clases partiendo de una clase o de una jerarquía de clases preexistente (ya comprobadas y verificadas) evitando con ello el rediseño, la modificación y verificación de la parte ya implementada. La herencia facilita la creación de objetos a partir de otros ya existentes e implica que una subclase obtiene todo el comportamiento (métodos) y eventualmente los atributos (variables) de su superclase.

En nuestros objetos es fácil implementar la herencia, basta con agregar la palabra clave extends y específicar la clase padre. Pero en una base de datos relacional no siempre queda claro cómo debemos implementar la herencia. Datanucleus (JDO) nos ofrece 4 opciones:

  1. Cuando cada clase tiene su propia tabla en la base de datos: new-table
  2. Cuando los campos de la clase padre son almacenados en la tabla del hijo: subclass-table
  3. Cuando los campos del hijo son almacenados en la tabla del padre: superclass-table
  4. A partir de JDO3.1, cuando cada clase tiene su propia tabla y esta contiene todos los campos (incluídos los de la clase padre): complete-table

Supongamos que tenemos la entidad Trabajador de la cual derivan las entidades Empleado y Meritorio. Nuestras clases quedarían de la siguiente manera:

public abstract class Trabajador {
   private String id;
   private String departmento;
}
public class Empleado extends Trabajador {
   private float salario;
}
public class Meritorio extends Trabajador {
   private Date fechaTermino;
}

Las tablas para las distintas estrategias que ofrece Datanucleus (JDO) serían:

new-table

Trabajador
id departamento
Empleado
idTrabajador salario
Meritorio
idTrabajador fechaTermino

subclass-table

Empleado
id departamento salario
Meritorio
id departamento fechaTermino

superclass-table

Trabajador
id departamento tipo salario fechaTermino

complete-table

Trabajador
id departamento
Empleado
id departamento salario
Meritorio
id departamento fechaTermino

Finalmente mostraré cómo anotar nuestras clases para implementar la estrategia superclass-table, que es el caso particular que se me presentó.

@PersistenceCapable
@Discriminator(strategy=DiscriminatorStrategy.VALUE_MAP, column="tipo")
public abstract class Trabajador {
   private String id;
   private String departmento;
}
@PersistenceCapable
@Inheritance(strategy=InheritanceStrategy.SUPERCLASS_TABLE)
@Discriminator(value="EMPLEADO")
public class Empleado extends Trabajador {
   private float salario;
}
@PersistenceCapable
@Inheritance(strategy=InheritanceStrategy.SUPERCLASS_TABLE)
@Discriminator(value="MERITORIO")
public class Meritorio extends Trabajador {
   private Date fechaTermino;
}

Fuentes:

http://www.datanucleus.org/products/datanucleus/jdo/orm/inheritance.html#superclasstable
http://www.datanucleus.org/products/accessplatform/jdo/orm/inheritance.html
https://developers.google.com/appengine/docs/java/datastore/jdo/dataclasses#Inheritance
http://es.wikipedia.org/wiki/Herencia_(programaci%C3%B3n_orientada_a_objetos)

En el diseño de bases de datos relacionales, se llama clave primaria a un campo o a una combinación de campos que identifica de forma única a cada fila de una tabla. No pueden haber dos filas en una tabla que tengan la misma clave primaria.
Un ejemplos de claves primarias es el ISBN (asociado a un libro).

Supongamos que tenemos una entidad Usuario que es identificada por 2 propiedades: id e idJuzgado. Para especificar la llave compuesta en Datanucleus lo haríamos de la siguiente manera:

@PersistenceCapable(objectIdClass=Usuario.ComposedIdKey.class)
public class Usuario {

public static class ComposedIdKey implements Serializable
{
    public Integer id;
    public String idJuzgado;

    public ComposedIdKey ()
    {
    }

    /**
     * Constructor accepting same input as generated by toString().
     */
    public ComposedIdKey(String value)
    {
        StringTokenizer token = new StringTokenizer (value, "::");
        token.nextToken();               // className
        this.id = Integer.parseInt(token.nextToken()); // field1
        this.idJuzgado = token.nextToken(); // field2
    }

    public boolean equals(Object obj)
    {
        if (obj == this)
        {
            return true;
        }
        if (!(obj instanceof ComposedIdKey))
        {
            return false;
        }
        ComposedIdKey c = (ComposedIdKey)obj;
        return id.equals(c.id) && idJuzgado.equals(c.idJuzgado);
    }

    public int hashCode ()
    {
        return this.id.hashCode() ^ this.idJuzgado.hashCode();
    }

    public String toString ()
    {
        // Give output expected by String constructor
        return this.getClass().getName() + "::"  + this.id + "::" + this.idJuzgado;
    }
}

@PrimaryKey
Integer id;
@PrimaryKey
String idJuzgado;
String nombre;
String apellidoPaterno;
String apellidoMaterno;

public Usuario() {
}

public Integer getId() {return id;}
public void setId(Integer id) {this.id = id;}
public String getNombre() {return nombre;}
public void setNombre(String nombre) {this.nombre = nombre;}
public String getApellidoPaterno() {return apellidoPaterno;}
public void setApellidoPaterno(String apellidoPaterno) {this.apellidoPaterno = apellidoPaterno;}
public String getApellidoMaterno() {return apellidoMaterno;}
public void setApellidoMaterno(String apellidoMaterno) {this.apellidoMaterno = apellidoMaterno;}
}

Notesé el uso de la clase Interna Usuario.ComposedIdKey en el parámetro de la anotación @PersistenceCapable y el uso de 2 anotaciones @PrimaryKey en las propiedades correspondientes.

Para realizar la consulta de un Objeto con una clave primaria compuesta debemos utilizar la sobrecarga del método getObjectById de la siguiente forma:


Usuario usuario=null;
 PersistenceManager pm = PMF.get().getPersistenceManager();
 Transaction tx = pm.currentTransaction();
 try{
 tx.begin();
 usuario = (Usuario) pm.getObjectById(new Usuario.ComposedIdKey(Usuario.ComposedIdKey.class.getName()+"::"+id+"::"+idJuzgado), false);
 tx.commit();
 }finally{
 if(tx.isActive()){
 tx.rollback();
 }
 pm.close();
 }

si tratas de utilizar el método getObjectById de la siguiente forma

pm.getObjectById(Usuario.class,new Usuario.ComposedIdKey(Usuario.ComposedIdKey.class.getName()+"::"+id+"::"+idJuzgado));

te arrojará una excepción parecida a la siguiente

javax.jdo.JDOUserException: Unable to create Object Identity for class “server.model.Usuario” since key is of an unsupported type (server.model.Usuario$ComposedIdKey

Fuentes:
http://www.datanucleus.org/products/datanucleus/jdo/primary_key.html
http://www.datanucleus.org/products/datanucleus/jdo/orm/compound_identity.html
http://es.wikipedia.org/wiki/Clave_primaria
http://book.javanb.com/using-and-understanding-java-data-objects/LiB0035.html

Uitlizo Jackson para serializar objetos al formato JSON y enviarlos al cliente mediante servicios REST. A veces olvido, sobretodo al inicio de un proyecto, que por default Jackson intenta serializar mis objetos con un BeanSerializer. Esto significa que mi clase debe ser un JavaBean, es decir, tener un constructor sin argumentos y ‘getters’ y ‘setters’ para las propiedades que me interesa sean incluídas en la respuesta. Si tu clase no cumple estas condiciones, te arrojará la siguiente excepción:

org.codehaus.jackson.map.JsonMappingException: No serializer found for class mx.com.apestudio.videohaus.server.model.Video and no properties discovered to create BeanSerializer