Pregunta

Estoy usando Play Framework 2.1.5 en una aplicación Java.

Tengo un componente de vista que toma una lista de objetos genéricos como parámetro.En este componente, quiero iterar en la lista y obtener algunas propiedades de cada elemento.

Esto se vería así:

@(elements: List[_])

@for((element, i) <- elements.view.zipWithIndex) {
    @i
    @element.id
    @element.name
}

(Necesito esos 3 valores)

Pero por supuesto, element.id y element.name no se compilaría incluso si el tipo de objetos que puse en la lista contuviera estos métodos.Entonces hice esto:

@for((element, i) <- elements.view.zipWithIndex) {
    @defining(
        ViewsUtils.getGenericElementId(element),
        ViewsUtils.getGenericElementName(element)) {
            case (id, name, something) =>
                @i
                @id
                @name
        }
}

Y en una clase de utilidad Java:

public final class ViewsUtils {

    public static String getGenericElementId(Object object) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        return object.getClass().getMethod("getId").invoke(object).toString();
    }

    public static String getGenericElementName(Object object) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        return object.getClass().getMethod("getName").invoke(object).toString();
    }
}

Esto funciona, pero sé que no es correcto porque podría generar una RuntimeException en caso de que uno de estos métodos no existiera para el tipo de objeto que puse en la lista.

Aquí están mis suposiciones:

  1. Lanzando los elementos

  2. Usando herencia

  3. Como solo necesito 2 propiedades de cada objeto (id y nombre), podría usar un mapa, pero necesito el índice del bucle (¿es posible obtenerlo de un mapa?) y no funcionaría si lo necesitara más de 2 propiedades.

  4. Quizás Scala proporcione la sintaxis para este tipo de cosas.

O tal vez simplemente estoy mirando en la dirección equivocada.

Gracias por su ayuda.

¿Fue útil?

Solución

Ok, eso es demasiado para un comentario, así que me arriesgaré a publicarlo como respuesta.

Suponiendo que nunca deseas obtener un RuntimeException usted mencionó que tiene sentido que su objeto implemente alguna interfaz (o mezcle un rasgo, como se dice en Scala), por lo que no correrá el riesgo de obtener una excepción y ya no necesitará reflexión para obtener valores.

Supongamos que declaras tal rasgo:

trait GenericObject {
  val id: Long
  val name: String
}

Luego declaras algunas clases de casos:

case class A(id: Long, name: String, someOtherField: SomeType) extends GenericObject {
  //your implementation
}

case class B(id: Long, name: String) extends GenericObject

case class C(id: Long, name: String) extends B(id, name)

Ahora puedes cambiar tu plantilla de esta manera:

@(elements: List[GenericObject])

@for((element, i) <- elements.view.zipWithIndex) {
  @i
  @element.id
  @element.name
}

Y deberías pasar la lista de GenericObjects a su plantilla:

val myObjects: List[GenericObject] = List(A(1, "A name"), B(2, "B name"), C(3, "C name"))
Ok(your_template.scala.html(myObjects))
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top