# java.lang.UnsupportedClassVersionError



## BlubBlub (26. Okt 2011)

Hi,

ich habe folgendes Problem:
Ich habe ein Plugin Fähiges System entwickelt.

Ich habe eine Starter Klasse geschrieben, welche die main Funktion beinhaltet.
Diese Starter Klasse lädt aus einem Plugin Ordner alle dort befindlichen Plugins und führt sie aus.
Damit ein Dritter ein Plugin schreiben kann, habe ich eine Api.jar erstellt die das notwendige Interface "ExternalFunction" enthält, welches alle Plugins implementieren müssen.


```
Api.jar
   |----------> META-INF
   |                |----------> MANIFEST.MF
   |
   |----------> interfaces
                    |----------> ExternalFunction.class
```

Nachdem ein Dritter nun ein Klasse geschrieben hat, welche das Interface implementiert, kompiliert er dieses.

Dazu gibt er beispielsweise auf der Windows Konsole folgendes ein:
javac -classpath "Pfad\Zur\Api.jar" "Pfad\Zur\MyPlugin.java"

Anschließend packt man die MyPlugin.class Datei die man hieraus erhält in ein jar-Archiv und diese legt man in den Plugin Ordner.
Beim Starten des Programm mit der main Function wird nun das Plugin geladen. 

Die Starter Klasse mit der Main Funktion habe ich in Eclipse geschrieben. Dieses verwendet JRE 1.6.

Das Problem: Führe ich in Eclipse die Starter Klasse aus, so funktioniert alles wunderbar, wenn das von einem Dritten geschrieben Plugin mit einem JDK der Version 1.6 kompiliert wurde. 
Das in der Api.jar geschrieben Interface welches ich dem Dritten mitliefer wurde von mir auc über das JDK der Version 1.6 kompiliert.
Hat der Dritte aber sein Plugin mit einem JDK der Version 1.7 kompiliert und führt, dann das Hauptprogramm aus, dann kommt es zu einer:
Exception in thread "main" java.lang.UnsupportedClassVersionError: MyPlugin : Unsupported major.minor version 51.0

Sprich:
C:\Program Files\Java\jdk1.6.0_29\bin\javac -classpath "Pfad\Zur\Api.jar" "Pfad\Zur\MyPlugin.java"
(Das Hauptprogramm wird beim Laden der Klasse KEINEN java.lang.UnsupportedClassVersionError werfen)

C:\Program Files\Java\jdk1.7.0_01\bin\javac -classpath "Pfad\Zur\Api.jar" "Pfad\Zur\MyPlugin.java" 
(Hierbei wird nachher beim Laden der Klasse ein  java.lang.UnsupportedClassVersionError  geworfen)

Hierhin sehe ich aber ein Problem für die späteren Plugin Entwickler. Denn es kommen ja immer wieder
mal neue Version des JDK heraus. Und ich denke mal, nicht dass ein Entwickler alle JDK Versionen auf seinem Rechner haben wird sondern in der Regel die neueste.
Um aber ein Plugin für meine Hauptprogramm schrieben zu können muss er offensichtlich eine JDK der Version 1.6 verwenden ansonsten kommt es zur oben genannten Exception. 
Irgendwie verstehe ich dieses Konzept aber nicht, denn ich fänds irgendwie logischer wenn die Plugins die mit JDK 1.7 oder höher entwickelt wurden abwärtskompatibel sein sollten, und nicht unbedingt mit JDK 1.6 zu entwickeln sind. Dem ist halt aber nicht so.
Muss ich dem Dritten jetzt also jedes mal die JDK Version 1.6 mitgeben damit er seine PluginKlasse kompilieren kann, bzw. muss ich ihm sagen dass er sich diese JDK Version runterladen muss, damit später keine Exception geworden werden. 



```
package starter;


import interfaces.ExternalFunction;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;

import javax.swing.JOptionPane;


public class Starter 
{
	public static void main(String[] args)
	{		
		try 
		{			  
			ArrayList<ExternalFunction> externalFunctionArrayList = new ArrayList<ExternalFunction>();
			
			File pluginFile = new File("C:\\Users\\Ich\\Desktop\\MyProgram2\\Plugins");
			File[] pluginJars = pluginFile.listFiles(new JARFileFilter());
			URL[] urls = new URL[pluginJars.length];
  
			for (int i = 0; i < pluginJars.length; i++)
			{ 
    			urls[i] = pluginJars[i].toURI().toURL();
				System.out.println(urls[i]);
			}
			  
			URLClassLoader urlClassLoader = new URLClassLoader(urls);
			
			for(int i=0; i <pluginJars.length; i++)
			{
				JarInputStream jarInputStream = null;
				try 
				{
					jarInputStream = new JarInputStream(new FileInputStream(pluginJars[i]));
					JarEntry jarEntry = jarInputStream.getNextJarEntry();
					
					while(jarEntry != null)
					{
						if(jarEntry.getName().toLowerCase().endsWith(".class"))
						{
							String clazzLocation = jarEntry.getName().substring(0, jarEntry.getName().length()-6).replace('/', '.');
							Class<?> clazz = urlClassLoader.loadClass(clazzLocation);
							Object object = clazz.newInstance();
							  
							if(object instanceof ExternalFunction)
								externalFunctionArrayList.add((ExternalFunction)object);
						}
						
						jarEntry = jarInputStream.getNextJarEntry();
					}
				}
				catch (FileNotFoundException e)
				{
					e.printStackTrace();
				}
				catch (IOException e)
				{
					e.printStackTrace();
				}
				finally
				{
					try 
					{
						jarInputStream.close();
					} 
					catch (IOException e)
					{
						e.printStackTrace();
					}
				}
			}
			
			externalFunctionArrayList.get(0).doSomething();
		}
		catch (MalformedURLException e)
		{
			e.printStackTrace();
		} 
		catch (ClassNotFoundException e)
		{
			e.printStackTrace();
		}
		catch (InstantiationException e)
		{
			e.printStackTrace();
		} 
		catch (IllegalAccessException e)
		{
			e.printStackTrace();
		}
	}
}
```


----------



## maki (26. Okt 2011)

Was ist denn die Frage?

Wenn du nur ein JRE 1.6 auf deiner Kiste am laufen hast, kannst du eben keine Klassen ausführen die für Java 7 kompiliert wurden, ist doch logisch.


----------



## AFlieger (26. Okt 2011)

> Irgendwie verstehe ich dieses Konzept aber nicht, denn ich fänds irgendwie logischer wenn die Plugins die mit JDK 1.7 oder höher entwickelt wurden abwärtskompatibel sein sollten, und nicht unbedingt mit JDK 1.6 zu entwickeln sind. Dem ist halt aber nicht so.



In Java 7 sind Spracherweiterungen hinzugekommen. Stichwort "Project Coin". Wie soll das mit der Abwärtskompatibilität funktionieren?


----------



## Gast2 (26. Okt 2011)

Die sind ja auch abwärtskompatibel. Das heisst, dass man Java 6 Klassen in 7 nutzen kann und nicht umgekehrt. 

Was du versuchst (eine 7er Klasse in 6 zu nutzen) nennt man Aufwärtskompatibilität. Das geht natürlich nicht!


----------



## L-ectron-X (26. Okt 2011)

Man könnte da am Besten das Hauptprogramm bei neuen JDK-Versionen mit der jeweils aktuellen Version kompilieren und das Programm gleich eine Versionsnummer nach oben schalten, um anzuzeigen, dass es angepasst wurde.


----------



## AFlieger (26. Okt 2011)

@kappesf

du hast natürlich Recht. :toll:


----------



## FerFemNemBem (26. Okt 2011)

Halloechen,

Du kannst auch einfach den Hinweis (in der readme.txt o.ä.) geben, dass der Plugin-Ersteller mit "-target 1.6" compilieren soll. Sprach und Syntaxerweiterungen des 7er JDK kann er dann natuerlich nicht nutzen.

Gruss, FFNB.


----------



## BlubBlub (28. Okt 2011)

> Du kannst auch einfach den Hinweis (in der readme.txt o.ä.) geben, dass der Plugin-Ersteller mit "-target 1.6" compilieren soll. Sprach und Syntaxerweiterungen des 7er JDK kann er dann natuerlich nicht nutzen.



Ich hab folgende Eingabe gemacht:
javac -cp ..\Api.jar -target 1.6 MyPlugin.java

wobei ich mit jdk1.7.0_01 kompiliert habe.
Als Ausgabe erhalte ich allerdings auf der Konsole:
javac: target release 1.6 conflicts with default source release 1.7

Ich krieg die Datei also nicht kompiliert.
Das verstehe ich nicht ich dachte, ich könnte mit der Angabe -target 1.6 auch mit einer jdk1.7 Version
eine Klasse für ein jre der 1.6 Version erstellen.


----------



## maki (28. Okt 2011)

Es gibt ime nur eine Möglichkeit das wirklich sicher hinzubekommen:
Unter einem JDK 1.6 entwickeln, source und target auf 1.6 stellen.


----------



## FerFemNemBem (28. Okt 2011)

Halloechen,

dann stell mal noch source auf 1.6 also:

javac -cp ..\Api.jar -source 1.6 -target 1.6 MyPlugin.java

Dann hast Du eine vollstaendig 1.6 kompatibele Klasse - auch unter einem 1.7er JDK kompiliert.

Gruss, FFNB.


----------



## BlubBlub (28. Okt 2011)

Eingabe:
javac -cp ..\Api.jar -source 1.6 -target 1.6 MyPlugin.java

hmm, dann erhalte ich folgende Ausgabe:
warning: [options] bootstrap class path not set in conjunction with -source 1.6 
1 warning


----------



## FerFemNemBem (28. Okt 2011)

Halloechen,

dann setz den bootclasspath noch. Compiliert hat es aber trotz der Warnung oder?

Hier findest Du die javac Dokumentation. Dort wird auch auf Dein Problem eingegangen.

Sorry, muss jetzt hier erstmal los. Evtl. kann ich Dir heute Abend noch genaueres dazu schrieben...

// EDIT: noch kurz als Beispiel:

javac -cp ..\Api.jar -bootclasspath [Pfad_Zu_Deinem_1.6er_rt.jar] -source 1.6 -target 1.6 MyPlugin.java

Gruss, FFNB.


----------



## BlubBlub (28. Okt 2011)

Jau hast recht es wird zwar ne Warnung ausgeben aber die Datei wird dennoch kompiliert und funtkioniert auch richtig.

Hab mir jetzt nochmal ein paar Gedanken gemacht und paar Sachen ausprobiert.
Angenommen mein Hauptprogramm wurde mit JDK 1.6 kompiliert, PluginOne wurde ebenfalls mit JDK 1.6 kompiliert und PluginTwo mit JDK 1.7 
Urpsprünglich hatte ich die Befürchtung, dass ich dem Plugin Hersteller immer die JDK 1.6 mitgeben muss zum kompilieren seiner Plugins, da mein Hauptprogramm ebenfalls mit JDK 1.6 kompiliert wurde. Doch dies spielt überhaupt keine Rolle. Es ist durchaus zulässig, dass das Hauptprogramm mit JDK 1.6 kompiliert wurde und die Plugins mit höheren Versionen. 

Macht der User Regelmäßige Updates seiner JRE so wird er keine Schwierigkeiten haben Plugins die mit neuen JDK Versionen erstellt wurden auszuführen. 
Der Benutzer muss also immer mindestes die JRE Version haben welche gleich der höchsten kompilierten Klasse mit einer JDK Version ist.
Sprich benutzt das auszuführende Programm eine Klasse die mit einer JDK Version 1.7 kompiliert wurde, und gibt es keine andere Klasse die mit einer höheren Version kompiliert wurde, so muss der User ein JRE runterladen welches ebenfalls der Version 1.7 entspricht.

Sprich Plugin Entwickler muss sich keine Gedanken machen mit welcher JDK er seine Plugins kompiliert, solange der Benutzer, die aktuelleste JRE Version verwendet.

Somit funktioniert ja alles Bestens =)

Danke für dieTipps


----------

