2013-06-20 12 views
6

Wir vor kurzem Update auf Java 7 Update 25 von Update 21 und jetzt eine Nullzeigerausnahme auftreten, wenn SwingUtilities.isEventDispatchThread() von einem RMI-Thread aufgerufen wird, becuase AppContext.getAppContext () gibt null zurück.AppContext ist NULL von RMI-Thread mit Java 7 Update 25

java.lang.NullPointerException bei sun.awt.SunToolkit.getSystemEventQueueImplPP (Unknown Source) bei sun.awt.SunToolkit.getSystemEventQueueImplPP (Unknown Source) bei sun.awt.SunToolkit.getSystemEventQueueImpl (Unknown Source) bei java.awt.Toolkit.getEventQueue (Unknown Source) bei java.awt.EventQueue.isDispatchThread (Unknown Source) bei javax.swing.SwingUtilities.isEventDispatchThread (Unknown Source) bei ... ... bei sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Methode) um sun.reflect.NativeMethodAcce ssorImpl.invoke (Unbekannte Quelle) um sun.reflect.DelegatingMethodAccessorImpl.invoke (Unbekannte Quelle) um java.lang.reflect.Method.invoke (Unbekannte Quelle) um sun.rmi.server.UnicastServerRef.dispatch (unbekannte Quelle) um sun.rmi.transport.Transport $ 1.run (Unbekannte Quelle) um sun.rmi.transport.Transport $ 1.run (Unbekannte Quelle) um java.security.AccessController.doPrivileged (Native Methode) um sun.rmi .transport.Transport.serviceCall (Unknown Source) bei sun.rmi.transport.tcp.TCPTransport.handleMessages (Unknown Source) bei sun.rmi.transport.tcp.TCPTransport $ ConnectionHandler.run0 (Unbekannt Quelle) bei Sonne .rmi.transport.tcp.TCPTransport $ ConnectionHandler.run (Un Quelle) bei java.util.concurrent.ThreadPoolExecutor.runWorker (Unbekannt Quelle) bei java.util.concurrent.ThreadPoolExecutor $ Worker.run (Unbekannt Quelle) bei java.lang.Thread.run (Unknown Source) bekannt

Dieser Fehler ist nur von Web-Start vorhanden, wenn wir unsere Anwendung über eine IDE ausführen, ist es in Ordnung.

Hat jemand anderes in das hineingelaufen? Haben Sie eine Vorstellung davon, was im letzten Update bezüglich AppContext geändert wurde?

Es scheint, andere sind etwas damit zusammenhängende Fragen mit AppContext nach dem Update mit: https://forums.oracle.com/message/11077767#11077767

+0

kann ich nicht eine Lösung bieten, aber wir haben das gleiche Problem mit Java 7 Update 25. Wir haben eine Swing-basierte Anwendung, die mit Java Webstart verteilt und gestartet wird. Es fungiert auch als RMI-Server. Wenn ein eingehender RMI-Aufruf EventQueue.isDispatchThread aufruft, erhalten wir die gleiche Ausnahme: sun.awt.AppContext # getAppContext() scheint in dieser Situation null zurückzugeben. Es ist eine ernste Regression, die Java 7 Update 25 für unsere Anwendung nutzlos macht. Wenn wir versuchen, die Problemumgehung von Bug 4711515 anzuwenden, kommen wir einen Schritt weiter. Aber dann tritt das Nullpointer-Problem in JNLPClassLoader.getPermissions auf ... – Holger

+0

Das Nullpointer-Problem in JNLPClassLoader.getPermissons() wird hier erwähnt: http://stackoverflow.com/questions/17230773/java-7-update-25-makes-our -java-web-start-application-fail-mit-no-logging Es gibt etwas ernsthaft falsch, dass Update Release ... – Holger

+0

Wir haben wahrscheinlich ähnliche Problem hier: . In unserer Anwendung fungiert der Client auch als RMI-Server. –

Antwort

0

Es ist keine endgültige Antwort, aber es ist eine Abhilfe, die für mich funktioniert.

Die Anwendung muss die aktuelle AppContext in EVT speichern:

AppContext evtContext; //field 

    SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      evtContext = AppContext.getAppContext(); 
     } 
    }); 

Dann werden alle Anrufe zu SwingUtilities.invokeLater(..) von RMI Gewinde müssen mit benutzerdefinierten invokeLater2(Runnable rn) Verfahren ersetzt werden, die sun.awt.SunToolkit.invokeLaterOnAppContext(..,..) wie verwendet:

void invokeLater2(Runnable rn) { 
    if (AppContext.getAppContext() == null) { 
     logger.warning("AppContext is null, using EVT AppContext" 
      + " through SunToolKit"); 
     sun.awt.SunToolkit.invokeLaterOnAppContext(evtContext, rn); 
    } else { 
     SwingUtilities.invokeLater(rn); 
    } 
} 

Leider müssen alle Aufrufe von SwingUtilities.invokeLater (..) aus RMI-Threads ersetzt werden und das Programm ist jetzt auf die interne Sun JRE-API angewiesen.

Ich hoffe, Oracle wird bald Patches für die JRE 1.7.0.u25 zur Verfügung stellen, um dieses Problem anzugehen.

- Diese Problemumgehung wurde unter den Vorschlägen guruman in den Kommentaren here gemacht.

+0

1) Ich muss meinen Code mit Java 5 kompilieren und es gibt mir Fehler, wenn ich versuchte, sun.awt.SunToolkit.invokeLaterOnAppContext zu verwenden, war das etwas, das nach Java 5 hinzugefügt wurde? 2) Ich versuchte den Ansatz der Erstellung eines Threads, der zu einer bestimmten Thread-Gruppe gehört, und es funktionierte, aber ich kann diesen Ansatz wirklich nicht verwenden, da ich am Ende eine Menge Threads erstellen werde. 2.1) Gibt es eine Möglichkeit zu zuweisen, um einen einzelnen Thread zu erstellen und Aufgaben zuweisen 2.2) Gibt es eine Möglichkeit, Aufgaben zu den EDT ohne Verwendung von InvokeLater und InvokeAndWait – user1216750

+0

Eigentlich verwende ich Java 1.7.0 Update 21. Ich tat überprüfe den Code in früheren Java-Versionen nicht. Dies ist der Grund, warum ich persönlich keine internen JRE-Klassen verwenden möchte. –

1

Ich hatte das gleiche Problem mit Java3D als Java Web Start ausgeführt. Ich habe eine andere Lösung gefunden. Sie müssen Ihren eigenen InvokeLaterProcessor mit einer Warteschlange für Runnables vorbereiten. Es muss Thema erweitern und ups Runnables holen und sie in run-Methode verarbeiten:

public class InvokeLaterProcessor extends Thread { 

    private BlockingQueue<Runnable> queue=new ArrayBlockingQueue<Runnable>(1); 

    public InvokeLaterProcessor(String name) { 
    super(name); 
    } 

    public void invokeLater(Runnable runnable) { 
    try { 
     queue.put(runnable); 
    } catch (InterruptedException ex) { 
     log.warn("invokeLater interrupted"); 
    } 
    } 

    public void run() { 
    Runnable runnable=null; 
    do { 
     try { 
     runnable = queue.take(); 
     SwingUtilities.invokeLater(runnable); 
     } catch (InterruptedException ex) { 
     runnable=null; 
     } 
    } while(runnable!=null); 
    } 
} 

als alles, was Sie tun müssen, ist es in statischen einer Klasse zu erstellen, die in Hauptthread erstellt wird:

static { 
    invokeLaterProcessor=new InvokeLaterProcessor("MyInvokeLater"); 
    invokeLaterProcessor.start(); 
} 

und Prozess Runnables durch diesen Code:

invokeLaterProcessor.invokeLater(runnable); 

Sie brauchen nicht proprietäre

sun.awt.SunToolkit.invokeLaterOnAppContext(evtContext, rn) 
0

Hier ist eine Problemumgehung für JDK-8019274, in einer Dienstprogrammklasse verpackt.

Für uns war invokeAndWait() das große Problem. In diesem Beispiel ist die vorhandene Korrektur für invokeLater() und eine neue Korrektur für invokeAndWait() vorhanden.

Hinweise:

  • Sie werden init() früh in Ihrem main() Methode jnlp.jar
  • aufrufen müssen, bevor invokeLater() ruft!
  • Ersetzen Sie alle Anrufe an invokeLater() und invokeAndWait() mit diesen Anrufen

(Haftungsausschluss:.. Das aus dem Produkt ist Einige Aspekte dieser Lösung nicht auf Dich zutreffen)

public class JreFix { 
    private static String badVersionInfo = null; 
    private static AppContext awtEventDispatchContext = null; 
    private static AppContext mainThreadContext = null; 
    private static Boolean isWebStart = null; 
    private static BasicService basicService = null; 
    private static IntegrationService integrationService = null; 

    /** 
    * Call this early in main(). 
    */ 
    public static void init() { 
     if (isWebstart() && isApplicableJvmType()) { 
      String javaVersion = System.getProperty("java.version"); 

      if ("1.7.0_25".equals(javaVersion)) { 
       badVersionInfo = "7u25"; 
      } 
      else if ("1.7.0_40".equals(javaVersion)) { 
       badVersionInfo = "7u40"; 
      } 
      else if (javaVersion != null && "1.6.0_51".equals(javaVersion.substring(0,8))) { 
       badVersionInfo = "6u51"; 
      } 
      else if ("javaws-10.25.2.16".equals(System.getProperty("javawebstart.version"))) { 
       badVersionInfo = "Web Start 10.25.2.16"; 
      } 
     } 

     if (badVersionInfo != null) { 
      mainThreadContext = AppContext.getAppContext(); 
      try { 
       SwingUtilities.invokeAndWait(new Runnable() { 
        public void run() { 
         awtEventDispatchContext = AppContext.getAppContext(); 
        } 
       }); 
      } 
      catch (Exception e) { 
       displayErrorAndExit(null); 
      } 

      if (mainThreadContext == null || awtEventDispatchContext == null) { 
       displayErrorAndExit(null); 
      } 
     } 
    } 

    public static void invokeNowOrLater(Runnable runnable) { 
     if (hasAppContextBug()) { 
      invokeLaterOnAwtEventDispatchThreadContext(runnable); 
     } 
     else { 
      SwingUtilities.invokeLater(runnable); 
     } 
    } 

    public static void invokeNowOrWait(Runnable runnable) { 
     if (hasAppContextBug()) { 
      fixThreadAppContext(null); 
     } 

     try { 
      SwingUtilities.invokeAndWait(runnable); 
     } 
     catch (Exception e) { 
      // handle it 
     } 
    } 

    public static boolean hasAppContextBug() { 
     return isJreWithAppContextBug() && AppContext.getAppContext() == null; 
    } 

    public static void invokeLaterOnAwtEventDispatchThreadContext(Runnable runnable) { 
     sun.awt.SunToolkit.invokeLaterOnAppContext(awtEventDispatchContext, runnable); 
    } 

    public static void fixThreadAppContext(Component parent) { 
     try { 
      final Field field = AppContext.class.getDeclaredField("threadGroup2appContext"); 
      field.setAccessible(true); 
      Map<ThreadGroup, AppContext> threadGroup2appContext = (Map<ThreadGroup, AppContext>)field.get(null); 
      final ThreadGroup currentThreadGroup = Thread.currentThread().getThreadGroup(); 
      threadGroup2appContext.put(currentThreadGroup, mainThreadContext); 
     } 
     catch (Exception e) { 
      displayErrorAndExit(parent); 
     } 

     if (AppContext.getAppContext() == null) { 
      displayErrorAndExit(parent); 
     } 
    } 

    private static boolean isJreWithAppContextBug() { 
     return badVersionInfo != null; 
    } 

    private static void displayErrorAndExit(Component parent) { 
     JLabel msgLabel = new JLabel("<html>" + 
       "Our application cannot run using <b>Web Start</b> with this version of Java.<p><p>" + 
       "Java " + badVersionInfo + " contains a bug acknowledged by Oracle (JDK-8019274)."); 
     JOptionPane.showMessageDialog(parent, msgLabel, "Java Version Error", JOptionPane.ERROR_MESSAGE); 
     System.exit(1); 
    } 

    private static boolean isApplicableJvmType() { 
     String vendor = System.getProperty("java.vendor"); 
     String vmName = System.getProperty("java.vm.name"); 
     if (vendor != null && vmName != null) { 
      return vmName.contains("Java HotSpot") && 
        (vendor.equals("Oracle Corporation") || 
        vendor.equals("Sun Microsystems Inc.")); 
     } 

     return false; 
    } 

    private static boolean isWebstart() { 
     if (isWebStart == null) { 
      try { 
       basicService = (BasicService) ServiceManager.lookup("javax.jnlp.BasicService");    
       isWebStart = true; 
      } 
      catch (UnavailableServiceException e) { 
       isWebStart = false; 
      }   

      try { 
       integrationService = (IntegrationService) ServiceManager.lookup("javax.jnlp.IntegrationService"); 
      } 
      catch (UnavailableServiceException e) { 
      } 
     } 
     return isWebStart; 
    } 
}