Nahtloses Debuggen der Scriptsprache Scala in einer Java Anwendung

Thomas Darimont

Erfahrenes Mitglied
Hallo,

hier mal ein Beispiel für nahtlose Integration einer Scriptsprache (Scala: http://www.scala-lang.org/) in Java am Beispiel
einer Debugging Session mit dem Eclipse Scala Plugin: http://www.scala-lang.org/downloads/eclipse/.

Wenn man in einer Java Anwendung große Teile Scripten möchte, ist es IMHO sehr wichtig, dass die Scriptumgebung neben einer
guten Unterstützung von Code Inspection / Refactoring / Code Editing auch entsprechend guten Debugging Support bietet.
So hätte ich beispielsweise gern die Möglichkeit beim Debuggen einer Java Anwendung mit dem Java Debugger (scheinbar) nahtlos
auf den Script Debugger / Editor umzuschalten sobald Script Code ausgeführt wird-und genau das sieht man unten :)

Java:
/**
 * 
 */
package de.tutorials;

/**
 * @author Thomas.Darimont
 * 
 */
public class CallScalaFromJavaExample {

    /**
     * @param args
     */
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("de.tutorials.scala.ScalaMain");
        System.out.println("From Java...");
        System.out.println(clazz.getMethod("businessOperation", int.class).
                invoke(clazz.newInstance(), 5));
        
        
    }

}

Scala:
Code:
package de.tutorials.scala;



class ScalaMain {
  
    def main(args : Array[String]){
           //println("Hallo")
                //println(fak(5))
                
                
        }
        
        def fak(n: Int) : Int = {
            if(n == 0) return 1
                else return n * fak(n-1)
        }
        
        def businessOperation(n: Int) : Int = {
          println("toScala");
          return fak(n);
          
        }
}

Man beachte den schönen Stack-Trace :)

Ist fast so cool wie das nahtlose Debuggen von C / JNI / Java Anwendungen mit Eclipse JDT und CDT:
http://www.tutorials.de/forum/java/...wendungen-gemeinsam-debuggen-mit-eclipse.html

Hier noch ein Beispiel für Scripting mit Python/Jython:
http://www.tutorials.de/forum/java/246047-java-anwendungen-scripten-mit-python-und-jython.html

Gruß Tom
 

Anhänge

  • de.tutorials.training-scalaFromJava.zip
    2,4 KB · Aufrufe: 21
  • de.tutorials.training.scala.zip
    89 KB · Aufrufe: 23
  • InJava1.jpg
    InJava1.jpg
    30,4 KB · Aufrufe: 191
  • InScala2.jpg
    InScala2.jpg
    29,8 KB · Aufrufe: 129
  • InScala3.jpg
    InScala3.jpg
    29,9 KB · Aufrufe: 98
  • InJava4.jpg
    InJava4.jpg
    30,7 KB · Aufrufe: 105
Hier noch das gleiche mit Groovy mit etwas umständlicherem StackTrace.

Java:
Java:
/**
 * 
 */
package de.tutorials;

import java.lang.reflect.Method;

/**
 * @author Thomas.Darimont
 *
 */
public class CallGroovyFromJava {

    /**
     * @param args
     */
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("de.tutorials.GroovyMain");
        System.out.println("From Java...");
        Method method = clazz.getMethod("businessOperation", Object.class);
        System.out.println(method.invoke(clazz.newInstance(), 5));
    }

}

Groovy:
Code:
package de.tutorials;


class GroovyMain {

  static void main(args) {
    println "Hallo Welt";
    println fak(5);
  }
  
  
  public static fak(n){
      if(n==0) return 1
      else return n*fak(n-1)
  }
  

  public businessOperation(n) {
    println("toGroovy")
    return fak(n)
  }
}

Ein weitereres cooles Einsatzgebiet für Scriptsprachen ist Monitoring & Management via JMX über ne Script Console :)
http://www.tutorials.de/forum/java/251696-jconsole-mit-groovy-scripten.html

Gruß Tom
 

Anhänge

  • InJava_1.jpg
    InJava_1.jpg
    31,1 KB · Aufrufe: 53
  • InGroovy_1.jpg
    InGroovy_1.jpg
    30,5 KB · Aufrufe: 39
  • InGroovy_2.jpg
    InGroovy_2.jpg
    34,1 KB · Aufrufe: 39
  • InJava_2.jpg
    InJava_2.jpg
    31 KB · Aufrufe: 48
Aber für was braucht man das eine Scriptsprache in Java zu integrieren wenn man das selbe doch auch in Java lösen könnte? Sorry bin auf diesem Thema noch nicht so fit ;)
 
Hallo,

eine in einer Java Anwendung eingebettete Scriptsprache bietet u.a. den Vorteil, dass
man die in Scripts ausgelagerte Logik relativ einfach / schnell ändern kann ohne alles
wieder neu Kompilieren zu müssen. Kundenanpassungen wie beispielsweise spezifische
Validierungsregeln, Trigger in einem Workflow und Berechnungsroutinen lassen sich schnell direkt
vor Ort als Script definieren. Mit Scriptsprachen wird man in allen Konfigurations / Anpassungsaspekten
sehr flexibel.

Weiterhin bieten viele Scriptsprachen oft den Vorteil, dass man sich eleganter,kürzer / leicht verständlicher
im Code ausdrücken kann als in Java (Insbesondere bei JRUby, Jython, Groovy und Scala, uvm.) was die
Entwicklungszeit erheblich verkürzen kann.

Weiterhin bieten viele Scriptsprachen, insbesondere die
die direkt auf einer JVM laufen: http://www.robert-tolksdorf.de/vmlanguages.html , umfangreiche Unterstützung
für Java. Außerdem sind diese Sprachen oft noch viel einfacher zu lernen als Java weshalb Anfänger weniger
Probleme haben und schneller produktiv Code schreiben können.

Ich rede nicht davon komplette Anwendung nur mit einer Scriptsprache zu entwerfen, sondern vielmehr davon,
dass es sinnvoll ist die wenige Teile die oft geändert und von einer schnellen und einfachen Anpassbarkeit
profitieren mit einer Scriptsprache zu implementieren.

...und dann machts natürlich Sinn wenn man nahtlos von der einen Sprache in die andere übergehen kann, beispielsweise beim
Debuggen ;-)

Gruß Tom
 
Hallo Thomas,

Das Scala-Beispiel ist schön, gerade wg. des Debugging-Szenarios.

Was mich gerade wundert ist, dass du Scala als "Scriptsprache" bezeichnest ?!
Nicht alles, was nicht Java ist aber von dort aufgerufen wird, ist "Scripting".

Man würde doch Scala eher für Entwicklung von Komponenten nutzen, die man dann mit Java höchstens integriert, oder? (Bzw. eher umgekehrt, Scala zur Integration von legacy Java verwenden).
Scala ist IIUC entworfen, um Applikationssprache zu werden, zielt es doch auf Multithreading und Modularisierung.
(Und wenn erstmal Tools und Bibliotheken weiter ausgereift sind...)



Auch das analog entworfene Groovy-Beispiel ist ja eher kein Beispiel für Scripting, sondern lediglich für Embedding.

Der Groovy-Code hat bisher keine Kenntnis von der einbettenden Umgebung und müsste erst noch durch weitere Methodenaufrufe parametriert werden.
Umgekehrt hat der Java-Code zuviel Kenntnis über die Groovy-Klasse ...

Zudem muss in beiden Fällen (Scala/Groovy) der Code erst compiliert werden, damit das Ganze funktioniert.

Mag persönliche Einschätzung sein, aber Scripting ist für mich eher, wenn man ein nicht compiliertes Groovy-File über die GroovyScriptEngine startet und diesem ein Binding übergibt, so dass das Script auf die Applikation per API zugreift.
 
Hallo,

Was mich gerade wundert ist, dass du Scala als "Scriptsprache" bezeichnest ?!
Nicht alles, was nicht Java ist aber von dort aufgerufen wird, ist "Scripting".
schon klar... Script Sprache ist ein schwammiger Begriff zu dem es zahlreiche Definitionen gibt
-> http://de.wikipedia.org/wiki/Skriptsprache
http://java-source.net/open-source/scripting-languages
http://www.robert-tolksdorf.de/vmlanguages.html

Im Java "Speech" werden oft auch alle Sprachen die den JSR-223 Scripting Langauges for the JVM erfüllen
als Scripting Langauges bezeichnet.
https://scripting.dev.java.net/



Aber du hast schon recht eigentlich hätte ich im Thread Titel allgemein Languages for the JVM schreiben müssen ;-)

Mag persönliche Einschätzung sein, aber Scripting ist für mich eher, wenn man ein nicht compiliertes Groovy-File über die GroovyScriptEngine startet und
diesem ein Binding übergibt, so dass das Script auf die Applikation per API zugreift.
Das ist eine Form von Scripting aber mit Sicherheit nicht die einzige. Ich sehe da keinen unterschied ob ich nun ein
Scriptfile "adhoc" interpretieren, on-the-fly zur Laufzeit oder statisch zur Buildzeit kompiliere. Für mich macht das besondere an diesen Sprachen
aus, dass sie auf der JVM ausführbar sind, die Entwicklungszeit für einige Probleme (durch einfachere / mächtigere / klarer Sprachmöglichkeiten als Java)
erheblich verkürzen und sowohl statisch kompiliert als auch adhoc interpretiert werden können. Man hat hier also (theoretisch) die Möglichkeit Anwendungen
direkt Interaktiv "Live" zu Scripten oder mit kleinen vorbereiteten Scripts zu erweitern. Natürlich kann man das mit "normalem" Java auch haben (BeanShell / Compiler API)
aber da ist man an die IMHO teilweise recht umständliche Java Syntax gebunden.

Wo ich auch noch großes Potential beim "Scripting" sehe ist damit die Anwendung zu konfigurieren. Setzt man heute das Springframework zur Entwicklung von Java Anwendungen ein, so hat man in der Regel eine XML basierte Konfiguration (falls man nicht auf die Alternativen Konfigurationsmöglichkeiten wie Properties oder Spring Java Config ausweicht) in der man seine Komponenten, deren Abhängigkeiten und fachliche sowie technische Queschnittsbelange deklarativ hinterlegt. Cool wäre es hier IMHO die Konfiguration
nicht in Form von XML sondern direkt in der Scriptsprache hinzuschreiben. Damit könnte eine entsprechende IDE schon out-of-the Box entsprechenden Support leisten / Fehler finden etc :)

Beispielsweise könnte man mit scala's object-Sntax: object SomeComponent{ someDependency = someServiceReference... } eine IMHO ansehliche und praktische Alternative zu herkömmlichen Bean-Definitionen schaffen.

Script basierte Konfiguration wäre quasi Springs Java Config on Steriods ;-)

Man würde doch Scala eher für Entwicklung von Komponenten nutzen, die man dann mit Java höchstens integriert, oder? (Bzw. eher umgekehrt, Scala zur Integration von legacy Java verwenden).
Scala ist IIUC entworfen, um Applikationssprache zu werden, zielt es doch auf Multithreading und Modularisierung.
(Und wenn erstmal Tools und Bibliotheken weiter ausgereift sind...)
Sehe ich auch so. Wenn das Tooling (IDE Unterstützung) rund um Scala besser wird hat es IMHO großes potential Java (als Sprache) in einigen
Bereichen zu ersetzen.

Zudem muss in beiden Fällen (Scala/Groovy) der Code erst compiliert werden, damit das Ganze funktioniert.
Geht in Groovy / Scala auch AdHoc (interpretiert / kompiliert wird dann entsprechend on-the-fly)
Java:
/**
 * 
 */
package de.tutorials;

import groovy.lang.GroovyShell;
import scala.tools.nsc.Interpreter;
import scala.tools.nsc.Settings;

/**
 * @author Thomas.Darimont
 * 
 */
public class AdHocInterpretationExample {

    /**
     * @param args
     */
    public static void main(String[] args) {
        GroovyShell groovyShell = new GroovyShell();
        groovyShell.evaluate("println 'Hello from Groovy!'");

        new Interpreter(new Settings())
                .interpret("println(\"Hello from Scala!\")");

    }

}

Ausgabe:
Code:
Hello from Groovy!
Hello from Scala!

Gruß Tom
 
Hi Tom,

danke für den ausführlichen Kommentar.

Eine Anmerkung nur noch:

Mein Satz:
"Zudem muss in beiden Fällen (Scala/Groovy) der Code erst compiliert werden, damit das Ganze funktioniert."

Bezog sich nicht auf die Einbettbarkeit der Sprachen an sich, sondern darauf, dass die Art und Weise, wie du dies in deinen ersten Posts gemacht hast, kein Beispiel für Scripting als Anwendungsszenario darstellt. (Was ja der Anlass für meinen ersten Kommentar war).
Ein Shell/Interpreteraufruf war genau das, was ich als Scriptszenario meinte.

BTW: Die ursprünglich gezeigte Integration von Groovy in Java ist doch weitaus cleaner bzw. transparenter möglich, als mit dem reflektiven Beispiel.

Einfach im JavaCode:
Code:
package de.tutorials;

public class CallGroovyFromJava {

  public static void main(String[] args) throws Exception {
      GroovyMain myObject = new GroovyMain();
      System.out.println("From Java...");
      System.out.println( myObject.businessOperation(5) );
  }
}

Wie sieht es an der Stelle mit Scala aus? Muss man da den Aufwand über Reflection treiben, oder ist das auch nahtloser möglich? (Umgekehrt Java Klassen/Objekte in Scala zu verwenden, scheint ja recht flüssig zu gehen).
 
Hallo,

klar geht das:

Code:
package de.tutorials;

class Greeter {
    def sayHello(to:String){
           println("Hello " + to)       
        }
}

Java:
/**
 * 
 */
package de.tutorials;

/**
 * @author Thomas.Darimont
 *
 */
public class ScalaFromJava {

    /**
     * @param args
     */
    public static void main(String[] args) {
        Greeter greeter = new Greeter();
        greeter.sayHello("Tom");
    }

}

Ausgabe:
Code:
Hello Tom

Wenn ich nun in sayHello(...) einen Breakpoint anlege bleibt der Java Debugger leider nicht drin stehen...
da ist das Scala Eclipse Plugin noch etwas buggy IMHO.

//Edit unter Eclipse 3.3.1.1 bleibt der Java Debugger an der richtigen Stelle (laut Stacktrace) stehen jedoch sehe ich keinen ScalaCode.
Das hängt wohl mit der Fehlermeldung zusammen die ich da bekomme:
Code:
...
java.lang.ClassCastException: org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor cannot be cast to ch.epfl.lamp.sdt.ui.scalaeditor.ScalaEditor
at ch.epfl.lamp.sdt.ui.scalaeditor.SelectRulerAction.createAction(SelectRulerAction.java:84)
at org.eclipse.ui.texteditor.AbstractRulerActionDelegate.setActiveEditor(AbstractRulerActionDelegate.java:89)
at org.eclipse.ui.internal.handlers.ActionDelegateHandlerProxy.updateDelegate(ActionDelegateHandlerProxy.java:292)
at org.eclipse.ui.internal.handlers.ActionDelegateHandlerProxy.isEnabled(ActionDelegateHandlerProxy.java:467)
at org.eclipse.ui.internal.handlers.ActionDelegateHandlerProxy.isEnabled(ActionDelegateHandlerProxy.java:435)
at org.eclipse.core.commands.Command.isEnabled(Command.java:831)
at org.eclipse.core.commands.Command.setHandler(Command.java:938)
at org.eclipse.ui.internal.handlers.HandlerAuthority.updateCommand(HandlerAuthority.java:535)
at org.eclipse.ui.internal.handlers.HandlerAuthority.sourceChanged(HandlerAuthority.java:496)
at org.eclipse.ui.internal.services.ExpressionAuthority.sourceChanged(ExpressionAuthority.java:305)
at org.eclipse.ui.internal.services.ExpressionAuthority.sourceChanged(ExpressionAuthority.java:285)
at org.eclipse.ui.AbstractSourceProvider.fireSourceChanged(AbstractSourceProvider.java:98)
at org.eclipse.ui.internal.services.ActivePartSourceProvider.checkActivePart(ActivePartSourceProvider.java:202)
at org.eclipse.ui.internal.services.ActivePartSourceProvider.access$0(ActivePartSourceProvider.java:142)
at org.eclipse.ui.internal.services.ActivePartSourceProvider$1.partDeactivated(ActivePartSourceProvider.java:90)
at org.eclipse.ui.internal.PartListenerList$4.run(PartListenerList.java:117)
...


Gruß Tom
 
Zurück