2011-10-25 10 views
6

¿Cómo puedo definir una clase interna anónima en Groovy? Vi referencias de que se suponía que eran compatibles con Groovy 1.7 y estoy usando 1.8.¿Cómo obtengo algo así como una clase interna anónima en Groovy?

thread = process.consumeProcessOutput(
    new Appendable() { 
    Appendable append(char c) { 
     app1.append(c) 
     app2.append(c) 
     return this 
    } 

    Appendable append(CharSequence csq) { 
     app1.append(csq) 
     app2.append(csq) 
     return this 
    } 

    Appendable append(CharSequence csq, int start, int end) { 
     app1.append(csq, start, end) 
     app2.append(csq, start, end) 
     return this 
    } 
    }) 

me sale una excepción con este código:

Caught: groovy.lang.MissingMethodException: No signature of method: java.lang.UNIXProcess.consumeProcessOutput() is applicable for argument types: (MyClass$1) values: [[email protected]] 
+0

bien, ¿qué tipo consumeconscessOutput? ¿Es una interfaz apta? –

+0

El término que describe su pregunta se llama "cierre", creo ... – djangofan

+0

Acepta Appendible y OutputStream – dromodel

Respuesta

0

esto funciona en una reciente índigo:

List l=new LinkedList() { 
      { 
       add(new Integer(1)); 
       add(new Integer(2)); 
      } 
     }; 
println l 
6

Este es un caso complicado ya que los métodos tienen que devolver el objeto en sí mismo como Appendable, y tiene un nombre de método sobrecargado que no funciona bien con groovy map para fundir la interfaz. La forma más simple y clara es, probablemente, utilizar una clase interna anónima, como lo haría en Java. Esto requiere una versión razonablemente actual del maravilloso (1.7 o posterior creo):

def testAppendable(Appendable appendable) { 
    println "appendable = $appendable" 
    appendable.append('a' as char). 
       append('b' as char). 
       append('c' as char) 
} 

testAppendable(new Appendable() { 
    Appendable append(char c) { 
     println "got $c" 
     this 
    } 
    Appendable append(CharSequence csq) { 
     this 
    } 
    Appendable append(CharSequence csq, int start, int end) { 
     this 
    } 
    String toString() { "inner class appendable" } 
}); 

Otra alternativa sería utilizar un Expando con cierres. Es un poco incómodo ya que solo una implementación por nombre de método se puede inicializar en el constructor. Tenga en cuenta que cualquier método de interfaz omitido tiene una implementación predeterminada que arroja una excepción.

testAppendable(new Expando(
    append: { char c -> 
     println "got $c" 
     delegate as Appendable 
    }, 
    toString: { -> 
     "expando appendable" 
    } 
) as Appendable) 

EDIT: con respecto a su ejemplo, no veo por qué fallaría. Mi prueba es casi idéntica y funciona sin problemas. ¿Cómo es la firma de process.consumeProcessOutput? Además, puede verificar que MyClass$1 implemente Appendable ejecutando javap MyClass$1.

+0

+1 Se agregó una [posible solución para hacerlo con un mapa] (http://stackoverflow.com/questions/7895545/how-do-i-get-something-like-an-anonymous-inner-class-in- groovy/7900626 # 7900626), pero seguiría tu ruta si tuviera la opción ;-) –

3

Como una adición a @ataylor's solution above, que es posible utilizar la notación Map as Appendable, pero es un poco de dulce de azúcar:

Dada la función de prueba:

def testAppendable(Appendable appendable) { 
    println "appendable = $appendable" 
    appendable.append('a' as char). 
       append("GROOVY",1,2). 
       append("TIM") 
} 

Podemos construir nuestra Anexables de esta manera:

def app 
app = [ append:{ a, b=null, c=null -> 
      if(a.grep(CharSequence)) a = a[ (b?:0)..<(c?:a.length()) ] 
      println "Got $a" 
      app 
     } ] as Appendable 

A continuación, ejecutar

testAppendable(app) 

Imprime

appendable = {[email protected]} 
Got a 
Got R 
Got TIM 

como se esperaba ...

Dependiendo de la situación, yo tendería a evitar hacerlo de esta manera, sin embargo, como la ruta de clase anónima es mucho más fácil de leer; -)

1

Su clase anónima debería estar bien. Puesto que todos los métodos que acabamos de delegar en otros dos casos de Appendable también se puede aplicar de esta manera:

final tee 
tee = { 
    final... args 
-> 
    app1.append(*args) 
    app2.append(*args) 

    return tee 
} as Appendable 

El operador hace * maravilloso para llamar a #append con el contenido de args como sus argumentos.

El MissingMethodException que está recibiendo es porque #consumeProcessOutput toma dos argumentos: uno para STDOUT y otro para STDERR.También solo lee lo suficiente de la salida para evitar que el proceso se bloquee, por lo que probablemente no sea lo que quiere aquí. Pruebe #waitForProcessOutput en su lugar.

final app1 = new StringBuilder() 
final app2 = new StringBuilder() 

final tee 
tee = { 
    final... args 
-> 
    app1.append(*args) 
    app2.append(*args) 

    return tee 
} as Appendable 

final cmd = 'ps a' 
final p = cmd.execute() 

p.waitForProcessOutput tee, tee 

println '*' * 80 
println app1 
println '*' * 80 
println app2 
Cuestiones relacionadas