Si no desea refactorizar el código y puede usar Java 8, es posible usar referencias de métodos.
Primero una demostración simple (disculpe las clases internas estáticas)
public class JavaApplication14
{
static class Baz
{
private final int _int;
public Baz(int value){ _int = value; }
public int getInt(){ return _int; }
}
static class Bar
{
private final Baz _baz;
public Bar(Baz baz){ _baz = baz; }
public Baz getBar(){ return _baz; }
}
static class Foo
{
private final Bar _bar;
public Foo(Bar bar){ _bar = bar; }
public Bar getBar(){ return _bar; }
}
static class WSObject
{
private final Foo _foo;
public WSObject(Foo foo){ _foo = foo; }
public Foo getFoo(){ return _foo; }
}
interface Getter<T, R>
{
R get(T value);
}
static class GetterResult<R>
{
public R result;
public int lastIndex;
}
/**
* @param args the command line arguments
*/
public static void main(String[] args)
{
WSObject wsObject = new WSObject(new Foo(new Bar(new Baz(241))));
WSObject wsObjectNull = new WSObject(new Foo(null));
GetterResult<Integer> intResult
= getterChain(wsObject, WSObject::getFoo, Foo::getBar, Bar::getBar, Baz::getInt);
GetterResult<Integer> intResult2
= getterChain(wsObjectNull, WSObject::getFoo, Foo::getBar, Bar::getBar, Baz::getInt);
System.out.println(intResult.result);
System.out.println(intResult.lastIndex);
System.out.println();
System.out.println(intResult2.result);
System.out.println(intResult2.lastIndex);
// TODO code application logic here
}
public static <R, V1, V2, V3, V4> GetterResult<R>
getterChain(V1 value, Getter<V1, V2> g1, Getter<V2, V3> g2, Getter<V3, V4> g3, Getter<V4, R> g4)
{
GetterResult result = new GetterResult<>();
Object tmp = value;
if (tmp == null)
return result;
tmp = g1.get((V1)tmp);
result.lastIndex++;
if (tmp == null)
return result;
tmp = g2.get((V2)tmp);
result.lastIndex++;
if (tmp == null)
return result;
tmp = g3.get((V3)tmp);
result.lastIndex++;
if (tmp == null)
return result;
tmp = g4.get((V4)tmp);
result.lastIndex++;
result.result = (R)tmp;
return result;
}
}
Salida
241
4
nulo
2
La interfaz Getter
es solo una interfaz funcional, puede usar cualquier equivalente.
GetterResult
class, descriptores de acceso eliminados para mayor claridad, contienen el resultado de la cadena de captadores, si existe, o el índice del último captador llamado.
El método getterChain
es una pieza de código simple y repetitiva que se puede generar automáticamente (o manualmente cuando sea necesario).
Estructuré el código para que el bloque repetido sea evidente.
Esta no es una solución perfecta ya que aún necesita definir una sobrecarga de getterChain
por número de captadores.
En su lugar, refactorizaría el código, pero si no puede y se encuentra usando cadenas de captadores largas, a menudo puede considerar construir una clase con las sobrecargas que llevan de 2 a, digamos, 10 captadores.
null
cheques, ya quewsObject.getFoo().getBar().getBaz().getInt()
es un olor a código. Lea lo que es la "Ley de Demeter" y prefiera refactorizar su código en consecuencia. Entonces el problema con losnull
cheques desaparecerá también. Y piensa en usarOptional
.