Jogar Quadro 2 - Scala modelo:Como chamar um método específico em um objeto genérico?
Pergunta
Eu estou usando Jogar Quadro 2.1.5 em uma aplicação Java.
Eu tenho uma componente de vista que leva uma lista de objectos genéricos como um parâmetro.Neste componente, o que eu quero para iterar na lista e obter algumas propriedades de cada elemento.
Isso ficaria algo como isso:
@(elements: List[_])
@for((element, i) <- elements.view.zipWithIndex) {
@i
@element.id
@element.name
}
(Eu preciso desses 3 valores)
Mas, é claro, element.id
e element.name
não seria compilar, mesmo se o tipo de objetos que eu coloquei na lista continha estes métodos.Então eu fiz isso:
@for((element, i) <- elements.view.zipWithIndex) {
@defining(
ViewsUtils.getGenericElementId(element),
ViewsUtils.getGenericElementName(element)) {
case (id, name, something) =>
@i
@id
@name
}
}
E em uma Java da classe de utilitário:
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();
}
}
Isso funciona, mas eu sei que não é certo, porque ele poderia jogar uma RuntimeException em caso de um destes métodos não existe para o tipo de objeto que eu coloquei na lista.
Aqui estão os meus suppositons:
Fundição de elementos
Usando herança
Como eu só preciso de 2 propriedades de cada objeto (id e nome), eu poderia usar um mapa, mas eu preciso que o índice de ciclo (é possível obtê-lo a partir de um mapa?) e ele não iria funcionar se eu precisava de mais do que 2 propriedades.
Talvez Scala fornece a sintaxe para este tipo de coisas.
Ou talvez eu só estou olhando na direção errada.
Obrigado por sua ajuda.
Solução
Ok, isso é um pouco demais para um comentário, então eu vou risco para publicá-la como uma resposta.
Supondo que você deseja nunca ter uma RuntimeException
você mencionou faz sentido que o objeto de implementar alguma interface (ou mistura em uma característica, como é dito no Scala), assim você não corre o risco de ficar uma exceção e não há mais necessidade de reflexão para obter valores.
Suponha que, declarar tal traço:
trait GenericObject {
val id: Long
val name: String
}
Em seguida, declarar alguns casos classes:
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)
Agora você pode mudar o seu modelo como esse:
@(elements: List[GenericObject])
@for((element, i) <- elements.view.zipWithIndex) {
@i
@element.id
@element.name
}
E você deve passar a lista de GenericObject
s para o seu modelo:
val myObjects: List[GenericObject] = List(A(1, "A name"), B(2, "B name"), C(3, "C name"))
Ok(your_template.scala.html(myObjects))