Annotations / Reflection / Invokation / Vererbung

w00t

Grünschnabel
Hallo und guten Morgen,
ich beschreibe mal mein Programm, und dann folgt die Frage:

Ich habe eine Art "Framework" für mich gebastelt, was Inhalte aus einer Datenbank abhängig von einer Modelklasse anzeigen kann. In der Modelklasse gibt es verschiedene Annotations, die beschreiben ob und wie ein Feld angezeigt wird.
Beispiel:

Modelklasse:
@ViewInTable(as = "maintitle", sort = 10)
@ViewInTab(as = "maintitle", tabname = "general", sort = 20, editable = true, type = ViewInTab.TYPE_AUTO)
private String maintitle = null;

Hier sind jetzt nur mal 2 Annotations der aktuell 4.

Beim Start des Programms wird die Klasse ausgelesen und es wird ein Array aufgebaut von Informationen. Dort wird z.B. das Feld an sich gespeichert (java.lang.reflect.Field) und die einzelnen Felder der Annotations. Also bei "ViewInTable" z.B. as und sort. Diese Liste nenne ich intern "FieldList", was eine erweiterte ArrayList ist, die mit "FieldModels" gefüllt wird.

Die beiden Annotations sind für folgendes da:
ViewInTab
Es wird ein JTabbedPanel erzeugt und für jeden tabname wird ein neuer Tab erstellt mit den dazugehörigen Inhalten. Das heißt für z.B. ein String wird ein normales JTextField erzeugt.

ViewInTable
Es wird eine Tabelle erstellt und für jedes Feld wird dort eine Spalte hinzugefügt.


Zum Schluss werden alle Informationen aus der Datenbank geladen und über ein eigenes TableModel in die Tabelle geschrieben. Die Datenbank wird auch durch Annotations gesteuert.
Wenn man nun auf einen Eintrag in der Tabelle doppelklickt, werden alle Einträge im TabbedPanel mit den Einträgen aus der Datenbank gefüllt.

Im gesamten Projekt wird sehr viel mit invokation und reflection gearbeitet.
Beispiel:
Die Datenbank wird beim erstmaligen Aufruf erstellt und über die Annotations werden die Tabellen gefüllt.
Dann kann der Benutzer Inhalte einpflegen.

Nun das Problem:
Es gibt aktuell nur ein Model, mit Standardinformationen. Beispiel:

MyModel

Integer id
String title
ArrayList fooBar

Mit dieser Klasse funktioniert alles super.

Diese Klasse habe ich nun Abstract gemacht und eine "DefaultMovieModel" draus gemacht. Nun möchte ich das Standardmodel erweitern um weitere Informationen zu laden, z.B. durch Plugins die andere beisteuern.

Es sieht also so aus:
abstract MovieModel

DefaultMovieModel extends MovieModel

TheMovieDBMovieModel extends MovieModel
private Integer exampleId = null;
...



Nun wird beim Programmstart also nicht nur das Standardmodel ausgelesen, sondern auch das Custommodel. Diese Informationen werden nun gemerged in meine FieldList. Alles so weit kein Problem.

Auch die Anzeige des Feldes im TabbedPanel ist kein Problem.

Probleme:
Das füllen der Felder in TabbedPanel und das füllen der Felder in der der Tabelle.

Java:
private final Vector<MovieModel> movies = new Vector<MovieModel>();
Hier wird folgendes gemacht:
Java:
	public Object getValueAt(final int rowIndex, final int columnIndex) {
		if(this.movies.size() > 0) {
			final MovieModel movie = this.movies.get(rowIndex);

			final Field field = ((Field) this.neededFields.get(Helper.getKeyFromMapPos(this.neededFields, columnIndex))[0]);

			Object o = null;
			try {
				o = Class.forName(movie.getClass().getCanonicalName()).getMethod("get" + Helper.ucfirst(field.getName())).invoke(
						movie);
			} catch(final IllegalArgumentException e) {
				e.printStackTrace();
			} catch(final SecurityException e) {
				e.printStackTrace();
			} catch(final IllegalAccessException e) {
				e.printStackTrace();
			} catch(final InvocationTargetException e) {
				e.printStackTrace();
			} catch(final NoSuchMethodException e) {
				e.printStackTrace();
			} catch(final ClassNotFoundException e) {
				e.printStackTrace();
			}
			Object resultVal = null;
			if(o == null) {
				resultVal = null;
			} else {
				if(o.getClass() == String.class) {
					resultVal = o;
				} else if(o.getClass() == Integer.class) {
					resultVal = Integer.toString((Integer) o);
				} else if(o.getClass() == File.class) {
					resultVal = ((File) o).getAbsolutePath();
				} else if(o.getClass() == ArrayList.class) {
					resultVal = ((ArrayList<Object>) o).size() > 0 ? Helper.implode(((ArrayList<Object>) o), ", ", null, null)
							: null;
				} else if(o.getClass() == Boolean.class) {
					resultVal = o;
				} else if((o.getClass() == ToolkitImage.class) && (o instanceof Image)) {
					final Point widthHeight = Helper.getProportionalWidthHeightImage(Helper.toBufferedImage((Image) o), 50.0,
							50.0);
					resultVal = new ImageIcon(((Image) o).getScaledInstance(widthHeight.x, widthHeight.y, Image.SCALE_SMOOTH));
				} else {
					resultVal = null;
				}
			}

			return resultVal;
		}
		return null;
	}

Da ich aber das Model "MovieModel" benutze und ja nicht weiß welches Model ich genau ansprechen muss, kann ich ja auch nicht auf die in MovieModel nicht vorhandenen Methoden zugreifen.


Ich habe mal ein Paar Projektdateien in den Anhang gehängt. Ich komm einfach gerade nicht weiter :-/

Ich weiß dass das sehr viel Text ist, aber vielleicht hat ja jemand eine Idee und Umsetzungstipps.


// EDIT:
Ich stelle auch gerne den kompletten Code zur Verfügung.
 

Anhänge

  • Projektdateien.zip
    8,9 KB · Aufrufe: 23
Zuletzt bearbeitet:
Zurück