File auf Gültigkeit überprüfen

Ich dachte, ich soll die Exception (IOException) in eine RuntimeException packen?
**EDIT**
-->IllegalArgumentException ist eh eine RuntimeException -.-

Wenn wir gleich dabei sind, hätte ich zu Exception allgm. noch eine Frage:
Ich habe in meinem Domain Model (welches eben das Interface von oben implementiert) einige Methoden, welche Exception werfen bzw sich auch untereinander aufrufen (also die Methoden) --> darunter sind eben IOExceptions, sowie RuntimeExceptions( u.a. HibernateExceptions) --> soll ich die nun alle bis nach oben zum Controller werfen? Jene Exception kann ich bzw brauch ich nicht behandeln, da alle mit einer Benutzereingabe zusammenhängen - sprich, ich muss dem Benutzer sagen können, warum ein Fehler aufgetreten ist (Falsche Eingabe, Datenbankfehler etc).

Ich möchte deine Geduld nicht übertrapazieren, aber irgendwie wirft dieser Thread immer mehr Fragen auf :(
 
Zuletzt bearbeitet:
Ich dachte, ich soll die Exception (IOException) in eine RuntimeException packen?
IllegalArgumentException IST eine RuntimeException. Die throws Klausel geht auch mit REs und hat nicht zur Folge, dass man die auch catchen muss. Meistens nutzt man sie nur mit normalen Exceptions, weil das der Compiler erzwingt.

Ich hab die nur drangenagelt damit sie im JavaDoc auftaucht und für den Client sichtbar ist. Er muss sie allerdings nicht explizit behandeln.

Wenn wir gleich dabei sind, hätte ich zu Exception allgm. noch eine Frage:
Ich habe in meinem Domain Model (welches eben das Interface von oben implementiert) einige Methoden, welche Exception werfen bzw sich auch untereinander aufrufen (also die Methoden) --> darunter sind eben IOExceptions, sowie RuntimeExceptions( u.a. HibernateExceptions) --> soll ich die nun alle bis nach oben zum Controller werfen? Jene Exception kann ich bzw brauch ich nicht behandeln, da alle mit einer Benutzereingabe zusammenhängen - sprich, ich muss dem Benutzer sagen können, warum ein Fehler aufgetreten ist (Falsche Eingabe, Datenbankfehler etc).

Ich möchte deine Geduld nicht übertrapazieren, aber irgendwie wirft dieser Thread immer mehr Fragen auf :(
Huh, die Fragen werden aber auch immer Allgemeiner. Exceptionhandling ist ein schweres Thema, mit paulschalen Anworten kommt man da nicht weit. Es gibt allerdings ein paar grundsätzliche Leitsätze:

Grundsätzlich würde ich RuntimeExceptions den normalen Exceptions vorziehen. Normale Exceptions sind eine recht komische Eigenart, die es in kaum einer anderen Programmiersprache gibt. REs "verschmutzen" den Clientcode wesentlich weniger. Die Grundlage der normalen Exceptions ist ja die Annahme, dass der (direkte) Client die Exception wirklich behandlen kann. Das ist aber in den seltensten Fällen wirklich der Fall.

In Legacycode findet man fast immer tonnenweise "throws Generic${InsertYourProjectOrCompanyNameHere}Exception" weil man meinte, die strenge Überprüfung wäre was tolles, weil sie den Entwickler dazu zwingt die Exceptions auch zu behandeln. Leider resultiert die "Behandlung" entweder in ziemlich hässlichen Signaturen oder massenweise leeren catch Blöcken.

Grundsätzlich ist es ja schon Aberwitzig. Exception heißt "Ausnahme", also etwas unerwartetes. Gleichzeitig soll ich mich dann aber mit etwas unerwartetem auseinandersetzen und damit Code schreiben, der das Unerwartete dann doch erwartet. Grausam...

Grundsätzlich hilft es eigentlich immer beim Design der Interfaces aus Clientsicht zu denken. Kann ich die Exception wirklich behandeln? Ja - checked Exception, Nein - runtimeException. Dabei ist es durchaus legitim und gewünscht die Fachlichkeit berücksichtigende Exceptionhierarchien zu bauen. Man sollte allerdings nicht zu schnell zu feingranular werden.

Was definitiv auch in REs gehört, sind "End-of-the-world" Szenarien. Hast du dich schonmal gefragt, warum bei Connection.close() (JDBC) eine checked SQLException fliegt? Was willst du dann noch machen? Das macht keinen Sinn. Am Thema File / IOExceptions scheiden sich ja auch die Geister. Auch hier kann man im Endeffekt in 90% der fälle nicht wirklich reagierun und muss sich mit so Krücken wie dem Wrapping in eine RE behelfen.

Das ist zum Beispiel auch der Grund, warum ich kein JDBC ohne Spring mehr machen mag. Dort fliegt eine DataAccessException, wenn irgendwas mit der DB schief geht. Klar, wenn ein SQL Statement falsch ist, ein Parameter eines NamedQuery fehlt, dann ist das ein Bug, Punkt. Da kann die Anwendung einfach nicht reagieren, da muss der Entwickler ran. Wenn die Connection mal nicht verfügbar ist kann man dann aber per AOP die Exception catchen und evtl einen Retrymechanismus starten. Mit REs hast du die Wahl, mit normalen Exceptions hässlichen Code.

Wow, ganz schön viel geworden. Am besten diskutiert sich sowas an einem konkreten Beispiel (wie du ja oben gesehen hast). Wo drückt denn genau der Schuh? IOExceptions an den Client zu reichen halte ich für rechtfertigungswürdig (d.h. ich würds grundsätzlich nicht machen, es mag aber Situationen geben, wo es Sinn macht).

Gruß
Ollie
 
Warum sollten IOExceptions nicht bis zum Controller vordringen? Ich muss doch schließlich in der View sagen warum nun dies und jenes nicht geklappt hat.

Also es geht darum dass ich eben ein Interface habe, welches benutzt wird, um "Tracks" in der DB persistent zu machen. Hierbei gibt es mehrere Varianten wie das vonstatten gehen soll, die da wären:
Code:
public void storeTracksFromFile(final String fPath, final String fName, final String jarPath, final String jarName,
			final String className, final Receiver receiver);

public void storeTracksFromFile(final String fPath, final String fName, final Class className,
			final Receiver receiver);

public void storeTracks(final List<Track> tList);

public void storeTrack(final Track track);
Also bei jenen Methoden wo ich schon Objekte bekomme (Track oder List<Track>) gehe ich damit einfach zu mehr Richtung DB und inserte jene --> hierbei kann ich bspw. eine HibernateException bekommen (bzw. wird jene Methode bei den anderen Varianten nach dem File lesen etc. auch benutzt) und was soll ich nun mit jener anfangen?
--> Ich muss wohl dem Benutzer zumindest mitteilen, dass eine Exception aufgetreten ist (bei der DB Interaktion) ? d.h. Ich muss/soll diese HibernateException auch bis zum Controller werfen?

Bei den beiden anderen Methode bekomme ich einmal einen Filenamen sowie den dazugehörigen Pfad und bei der anderen Methode kommt hierbei die Möglichkeit hinzu, dass man das Parsen des Files über ein externes JAR macht. Diese beiden Methoden haben wir in diesem Thread schon zur Genüge abgearbeitet.

Meine Frage bezieht sich einfach darauf, wie ich mit den Exceptions die da geworfen werden umgehen soll. da eigentlich jede einzelne einen Hinweis liefert, warum bspw. das File lesen oder das DB schreiben nicht funktioniert hat - und jenes müßte ich dann ja auch den Benutzer mitteilen (also nicht den stacktrace, jedoch zumindest warum es nicht funktioniert hat).

Wie soll ich mit den Datenbank Exceptions umgehen?
1. kann ich sie ja nicht wirklich behandeln und
2. wie soll ich dem Benutzer bescheid geben (Exception werfen?)

Beispiel Methode für store eines Tracks:
Code:
	public void storeTrack(final Track track) {
		Session session = HibernateUtil.getCurrentSession();
		TrackDAO trackDAO = new TrackDAO();
		TrackPointDAO trackPointDAO = new TrackPointDAO();
		try {	
			session.beginTransaction();
			trackDAO.setSession(session);	
			trackDAO.makePersistent(track);	
			trackPointDAO.setSession(session);
			for (TrackPoint point : track.getTrackPointList()) {
				point.setTrack(track);
				trackPointDAO.makePersistent(point);	
			}			
			session.getTransaction().commit();
		} catch (HibernateException e) {
			if (session.getTransaction() != null) {
				session.getTransaction().rollback();
				TrackControllerModel.LOGGER.error("exception occurred while storing tracks: ", e);
			}
		} finally {
			session = null;
			trackDAO = null;
		}
	}
Also das ist dann die Stelle wo in die DB geschrieben wird und hier stellt sich mir die Frage ob ich die Exception fangen soll oder weiterwerfen- bzw was ich werfen soll?
 
Zuletzt bearbeitet:
Warum sollten IOExceptions nicht bis zum Controller vordringen? Ich muss doch schließlich in der View sagen warum nun dies und jenes nicht geklappt hat.

Natürlich. Eine RE schlägt ja auch bis nach oben durch. Die Frage ist doch nur, ob sich das auch in den Methodensignaturen niederschlagen soll/muss. Eine IOException musst du durch alle Layer hinauf nach oben durchreichen und hast dann an jeder Methode "throws IOException" das ist zum einen sauhässlich, zum anderen passt die Exception dann in höheren Layern nicht mehr zur Abstraktion des Layers.

Okay, wie teilst du dann den Usern mit, dass eine Exception fliegt? Nehmen wir an, es handelt sich um eine Webanwendung. Dann landen REs ohne Handling direkt beim Benutzer und produzieren nette Tomcatfehlerseiten. Man kann allerdings über die web.xml Fehlerseiten für Exceptions definieren (für verschiedene Exceptions auch verschiedene Seiten), so dass man gezielt Bescheid geben kann, dass z.B. die DB weg ist und zusätzlich die Exception für die Auswertung durch den Admin loggt.

Also es geht darum dass ich eben ein Interface habe, welches benutzt wird, um "Tracks" in der DB persistent zu machen. Hierbei gibt es mehrere Varianten wie das vonstatten gehen soll, die da wären:
Code:
public void storeTracksFromFile(final String fPath, final String fName, final String jarPath, final String jarName,
			final String className, final Receiver receiver);

public void storeTracksFromFile(final String fPath, final String fName, final Class className,
			final Receiver receiver);

public void storeTracks(final List<Track> tList);

public void storeTrack(final Track track);
Also bei jenen Methoden wo ich schon Objekte bekomme (Track oder List<Track>) gehe ich damit einfach zu mehr Richtung DB und inserte jene --> hierbei kann ich bspw. eine HibernateException bekommen (bzw. wird jene Methode bei den anderen Varianten nach dem File lesen etc. auch benutzt) und was soll ich nun mit jener anfangen?
--> Ich muss wohl dem Benutzer zumindest mitteilen, dass eine Exception aufgetreten ist (bei der DB Interaktion) ? d.h. Ich muss/soll diese HibernateException auch bis zum Controller werfen?
Siehe oben. Du solltest entweder die Möglichkeiten der Clientplattform nutzen um RuntimeException zu catchen, oder an den zentralen Einstiegspunkten in die Anwendung von Hand RuntimeException catchen und dort die Fehlerverarbeitung platzieren.

Meine Frage bezieht sich einfach darauf, wie ich mit den Exceptions die da geworfen werden umgehen soll. da eigentlich jede einzelne einen Hinweis liefert, warum bspw. das File lesen oder das DB schreiben nicht funktioniert hat - und jenes müßte ich dann ja auch den Benutzer mitteilen (also nicht den stacktrace, jedoch zumindest warum es nicht funktioniert hat).

Nunja, das muss man differentiert sehen. Einen Benutzer interessiert im allgemeinen kein "Paramter 3 for NamedQuery Not Found" o.ä., wenn die Connection weg is usw. Grad dieser Lowlevel Krams geht nen Enduser nix an, ist also entweder "EndOfTheWorld" (Connection weg) oder Bug (NamedQuery Dingens...). Beides ist Info für Admins / Entwickler, daher loggen und weg.

Falls man wirklich detaillierte Fehlermeldungen geben will (Keine Rechte, Nicht lesbar o.ä.), kann man die auftretenden Fehler in eine eigene Exceptionhierarchie packen und dann an der gleichen Stelle (siehe oben) detaillierter fangen.

Was oft vergessen wird ist, dass man eigene Exceptions auch schön mit Contextinformationen anreichern kann, z.B. welches File kann nicht gelesen werden? Wenn du zum Beispiel file.canRead() abfragst und im Fehlerfall eine CanNotReadFileException (selber coden) wirfst und die mit dem dem zu lesenden File anreicherst, kannst du diese Exception oben auch speziell behandeln und die Informationen an den User weitertragen.

Wie soll ich mit den Datenbank Exceptions umgehen?
1. kann ich sie ja nicht wirklich behandeln und
2. wie soll ich dem Benutzer bescheid geben (Exception werfen?)

Beispiel Methode für store eines Tracks:
Code:
	public void storeTrack(final Track track) {
		Session session = HibernateUtil.getCurrentSession();
		TrackDAO trackDAO = new TrackDAO();
		TrackPointDAO trackPointDAO = new TrackPointDAO();
		try {	
			session.beginTransaction();
			trackDAO.setSession(session);	
			trackDAO.makePersistent(track);	
			trackPointDAO.setSession(session);
			for (TrackPoint point : track.getTrackPointList()) {
				point.setTrack(track);
				trackPointDAO.makePersistent(point);	
			}			
			session.getTransaction().commit();
		} catch (HibernateException e) {
			if (session.getTransaction() != null) {
				session.getTransaction().rollback();
				TrackControllerModel.LOGGER.error("exception occurred while storing tracks: ", e);
			}
		} finally {
			session = null;
			trackDAO = null;
		}
	}
Also das ist dann die Stelle wo in die DB geschrieben wird und hier stellt sich mir die Frage ob ich die Exception fangen soll oder weiterwerfen- bzw was ich werfen soll?

Klarer Fall: als RuntimeException weiterwerfen. HibernateException ist doch schon Runtime, oder? Und ganz oben halt irgendwo RuntimeException catchen.

Darf ich nochmal Spring erwähnen? Grad das Thema Datenbankzugriff ist gerade eins, was ziemlich oft vorkommt, und wo sich jede Menge gedanken gemacht haben. Das Problem der ORMapper ist, dass sie alle proprietäre Exceptions werfen. Wenn man jetzt z.B. eine Anwendung mit Hibernate schreibt, wirft die HibernateExceptions. Angenommen du hast noch 2 StoredProcedures, die du aber mit JDBC ansprechen musst. Das wirft logischerweise JDBCExceptions. 2 Probleme: wie handelst du die Exceptions sauber ohne catch (HibernateException e), catch (JDBCException e) zu machen? wie bekommst du beides in eine Transaktion?

Spring bietet mit seiner Abstraktion der Datenbankzugriffsschicht beides. Zum einen ein vereinheitlichtes Transaktionsmodell zum anderen (für dich wichtiger ;)) transformieren die Templateklassen (JDBCTemplate, HibernateTemplate) die technologiespezifischen (checked) Exceptions in eine einheitliche fachlichere Exceptionhierarchie. Das ist in heterogenen Umgebungen ein riesen Benefit.

Werden wir wieder konkret. Was für einen Client hast du? Web? Swing? Dann könnte ich evtl nochmal detaillierter helfen.

Gruß
Ollie
 
Guten Morgen!
Also betreffend Client ist zu sagen, dass es hierbei noch keinen gibt - es wird jedoch auch eine Webapplikation mit myFaces hinauslaufen.

Und was auch noch klar ist ist dass ich bspw eine IOException, welche in eine RuntimeException gewrapped wurde nicht als Fehlerseite ausgebe, sondern jene eigentlich fangen möchte und dann allgm Fehlermeldungen ausgeben möchte - sprich war die geworfene Exception eine IOExecption weiß ich, dass hierbei beim File lesen etwas nicht geklappt hat und teile dies mit - die Exception selbst, wird mit Log4J protokolliert - geht den Benutzer nicht unbedingt etwas an. Genauso verhält es sich dann wohl auch mit HibernateExceptions, hierbei werde ich auch nur eine allgm. Fehlermeldung ausgeben, jedoch muss ich halt wissen, von wo das Problem kommt (bzw wo eine Ausnahme auftrat). Ich stelle mir das halt so vor dass ich dort wo ich das Model im Controller anspreche eben einen try/catch Block habe und dort dann auf die entsprechenden Exceptions reagiere.
Kann man das so realisieren bzw kann ich die Exceptions wieder in ihre "Ursprungsform" wandeln? Also wenn ich eine IOException werfe und jene eben dafür in eine RE wrappe, kann ich jene dann im Controller wieder zurückwandeln?
Andernfalls packe ich meine Fehlermeldungen einfach in ein Bundles File und füge nur die Nummer/ den Namen des Fehlertextes der Exception hinzu und im Controller prüfe ich dann auf die Nummer und kenne den Fehler?

Also habe ich dich betreffend "IOException würde ich nicht an den Controller werfen" falsch verstanden - ich dachte ich dürfte selbige auch nicht in eine RuntimeException verpackt bis nach oben wergen - geklärt. Und betreffend Methodensignatur ist zu sagen, dass ich in meiner Implementierung des Interfaces in der Signatur die RE schon angebe, aber im Interface nicht - dient nur mir zur Hilfe, damit ich weiß, dass jene Methoden eine RE werfen.

Etwas würde mich auch noch interessieren:
Also in meiner Implementation des Interfaces gebe ich in der Methodensignatur an, dass eine RE (welche auch immer) geworfen wird, soll ich jene Angabe auch bei der aufrufenden Methoden (noch immer innerhalb der Interface Implementierung) machen?
Also so:
Code:
public void methodA throws IllegalArgumentException {
 this.methodB;
}

private int methodB throws IllegalArgumentException {
 throw new IllegalArgumentException("blah");
}

Und betreffend HibernateException, wie soll ich die dann weiter werfen, so:
Code:
public void storeTrack(final Track track) {
		Session session = HibernateUtil.getCurrentSession();
		TrackDAO trackDAO = new TrackDAO();
		TrackPointDAO trackPointDAO = new TrackPointDAO();
		try {	
			session.beginTransaction();
			trackDAO.setSession(session);	
			trackDAO.makePersistent(track);	
			trackPointDAO.setSession(session);
			for (TrackPoint point : track.getTrackPointList()) {
				point.setTrack(track);
				trackPointDAO.makePersistent(point);	
			}			
			session.getTransaction().commit();
		} catch (HibernateException e) {
			if (session.getTransaction() != null) {
				session.getTransaction().rollback();
				TrackControllerModel.LOGGER.error("exception occurred while storing tracks: ", e);
				throw new HibernateException("exception occurred while storing tracks: ", e);
			}
		} finally {
			session = null;
			trackDAO = null;
		}
Hierbei sollte ich ja die Exception einmal fangen, damit ich "aufräumen" kann (finally)?
 
Zuletzt bearbeitet:
Guten Morgen!
Also betreffend Client ist zu sagen, dass es hierbei noch keinen gibt - es wird jedoch auch eine Webapplikation mit myFaces hinauslaufen.

Und was auch noch klar ist ist dass ich bspw eine IOException, welche in eine RuntimeException gewrapped wurde nicht als Fehlerseite ausgebe, sondern jene eigentlich fangen möchte und dann allgm Fehlermeldungen ausgeben möchte - sprich war die geworfene Exception eine IOExecption weiß ich, dass hierbei beim File lesen etwas nicht geklappt hat und teile dies mit - die Exception selbst, wird mit Log4J protokolliert - geht den Benutzer nicht unbedingt etwas an. Genauso verhält es sich dann wohl auch mit HibernateExceptions, hierbei werde ich auch nur eine allgm. Fehlermeldung ausgeben, jedoch muss ich halt wissen, von wo das Problem kommt (bzw wo eine Ausnahme auftrat). Ich stelle mir das halt so vor dass ich dort wo ich das Model im Controller anspreche eben einen try/catch Block habe und dort dann auf die entsprechenden Exceptions reagiere.

Klingt nach nem vernünftigen Ansatz. Wenn das ganze in nem Tomcat läuft, kannst du z.B. auch einfach die Features der plattform nutzen um für HibernateExceptions eine Fehlerseite bereitzustellen, für andere RuntimeExceptions eine andere. Damit lassen sich auch Fehlertypen kategorisieren.

Unschön fänd ich in jedem Controller ein try { .. } catch (HibernateException e) { .. } catch (RuntimeException e) { .. }. Das ist dann wieder try catch Wahnsinn und du schreibst mehr code für das Exception Handling als für die eigentliche Logik.

Kann man das so realisieren bzw kann ich die Exceptions wieder in ihre "Ursprungsform" wandeln? Also wenn ich eine IOException werfe und jene eben dafür in eine RE wrappe, kann ich jene dann im Controller wieder zurückwandeln?

Klar kannst du Exceptions wrappen und dann oben wieder auspacken. Das hat allerdings den Nachteil dass du dann oben recht hässlich mit instanceof rumhantieren musst m entsprechende Fehlermeldungen zu produzieren. Sinnvollerweise macht man grobe Basisklassen, die schon die Kategorisierung beinhalten: DataAccessException, RemoteException usw. Da hinein kannst du die auftretenden checked Exceptions wrappen und über getCause() die Ursache in die Logs schreiben. Trotzdem reicht dann bei angenommen 5 "TopLevel" Exceptions ein try block mit 5 catch blöcken um die entsperchenden Fehlerseiten anzuspringen.

Weiterhin spricht dann nichts dagegen die Toplevel Exceptions nochmal zu untergliedern. Ann kanst du an der Stelle, an der du die checked Exception fängst entscheiden in welche "Stufe" in der Exceptionhierarchie du die checked Exception "einsortierst". Das ermöglicht dann evtl. nochmal feingranulareres abfassen der Exceptiontypen - sowohl für den Admin und das Log als auch für den Benutzer.

Andernfalls packe ich meine Fehlermeldungen einfach in ein Bundles File und füge nur die Nummer/ den Namen des Fehlertextes der Exception hinzu und im Controller prüfe ich dann auf die Nummer und kenne den Fehler?
Ich würde einen dedizierten ExceptionTranslator bauen, der dann die Exceptiontypen in BundleKeys übersetzt und du dann daraus die Messages zusammenbauen kannst.

Also habe ich dich betreffend "IOException würde ich nicht an den Controller werfen" falsch verstanden - ich dachte ich dürfte selbige auch nicht in eine RuntimeException verpackt bis nach oben wergen - geklärt. Und betreffend Methodensignatur ist zu sagen, dass ich in meiner Implementierung des Interfaces in der Signatur die RE schon angebe, aber im Interface nicht - dient nur mir zur Hilfe, damit ich weiß, dass jene Methoden eine RE werfen.
Klingt gut. Ich find, dass sie auch im Interface nicht stören, aber das ist Geschmackssache.

Etwas würde mich auch noch interessieren:
Also in meiner Implementation des Interfaces gebe ich in der Methodensignatur an, dass eine RE (welche auch immer) geworfen wird, soll ich jene Angabe auch bei der aufrufenden Methoden (noch immer innerhalb der Interface Implementierung) machen?
Also so:
Code:
public void methodA throws IllegalArgumentException {
 this.methodB;
}

private int methodB throws IllegalArgumentException {
 throw new IllegalArgumentException("blah");
}
Würde ich nicht tun und zwar su folgendem Grund: Es gibt kaum Fälle in denen du in der 2. oder 3. Indirektion was mit der Exception anfangen kannst. Will heißen: entweder der direkte Aufrufer kann was damit anfangen oder die Exception sollte recht weit oben zentral behandelt werden.

Aber auch das ist Geschmackssache. Throws Deklarationen sind so unfachlich, so technisch, daher lass ich sie sobald wie möglich weg, schrei sie aber so lang wie nötig dran. ;)

Und betreffend HibernateException, wie soll ich die dann weiter werfen, so:
Code:
public void storeTrack(final Track track) {
		Session session = HibernateUtil.getCurrentSession();
		TrackDAO trackDAO = new TrackDAO();
		TrackPointDAO trackPointDAO = new TrackPointDAO();
		try {	
			session.beginTransaction();
			trackDAO.setSession(session);	
			trackDAO.makePersistent(track);	
			trackPointDAO.setSession(session);
			for (TrackPoint point : track.getTrackPointList()) {
				point.setTrack(track);
				trackPointDAO.makePersistent(point);	
			}			
			session.getTransaction().commit();
		} catch (HibernateException e) {
			if (session.getTransaction() != null) {
				session.getTransaction().rollback();
				TrackControllerModel.LOGGER.error("exception occurred while storing tracks: ", e);
				throw new HibernateException("exception occurred while storing tracks: ", e);
			}
		} finally {
			session = null;
			trackDAO = null;
		}
Hierbei sollte ich ja die Exception einmal fangen, damit ich "aufräumen" kann (finally)?

Finally wird immer ausgeführt, auch wenn eine Exception fliegt. Daher reicht es in dem Fall, den Aufräumcode im finally Block zu haben und die HibernateException einfach durchrauschen zu lassen - du brauchst also gar keinen Catchblock. Die HibernateException nochmal zu wrappen ist auch nicht so sehr schön. Das sorgt dann für eine (eigentlich unnötige) Indirektion mehr im Stacktrace.

REINHAUN!
 
Klingt nach nem vernünftigen Ansatz. Wenn das ganze in nem Tomcat läuft, kannst du z.B. auch einfach die Features der plattform nutzen um für HibernateExceptions eine Fehlerseite bereitzustellen, für andere RuntimeExceptions eine andere. Damit lassen sich auch Fehlertypen kategorisieren.
Jop, möchte ich aber in diesem Fall nicht (wie schon erwähnt) :) .
Unschön fänd ich in jedem Controller ein try { .. } catch (HibernateException e) { .. } catch (RuntimeException e) { .. }. Das ist dann wieder try catch Wahnsinn und du schreibst mehr code für das Exception Handling als für die eigentliche Logik.

Klar kannst du Exceptions wrappen und dann oben wieder auspacken. Das hat allerdings den Nachteil dass du dann oben recht hässlich mit instanceof rumhantieren musst m entsprechende Fehlermeldungen zu produzieren. Sinnvollerweise macht man grobe Basisklassen, die schon die Kategorisierung beinhalten: DataAccessException, RemoteException usw. Da hinein kannst du die auftretenden checked Exceptions wrappen und über getCause() die Ursache in die Logs schreiben. Trotzdem reicht dann bei angenommen 5 "TopLevel" Exceptions ein try block mit 5 catch blöcken um die entsperchenden Fehlerseiten anzuspringen.
Also heißt das dass ich meine IOException und FileNotFoundException bspw in eine BasisException für diese Art von Exception packen soll? Namensvorschlag für diesen Fall?^^
Wo soll ich jene dann am besten in die jeweilige BasisException wrappen? Damit es seine Ordnung hat bspw bei den Interface Implementation Methoden?

Weiterhin spricht dann nichts dagegen die Toplevel Exceptions nochmal zu untergliedern. Ann kanst du an der Stelle, an der du die checked Exception fängst entscheiden in welche "Stufe" in der Exceptionhierarchie du die checked Exception "einsortierst". Das ermöglicht dann evtl. nochmal feingranulareres abfassen der Exceptiontypen - sowohl für den Admin und das Log als auch für den Benutzer.
Ich glaube das führt nun wohl doch zuweit und würde dazu führen, dass ich eine Lesung bei dir buchen müsste. Verstehe es also nicht unbedingt.

Ich würde einen dedizierten ExceptionTranslator bauen, der dann die Exceptiontypen in BundleKeys übersetzt und du dann daraus die Messages zusammenbauen kannst.
Klingt interessant, wie darf ich mir das vorstellen?

Würde ich nicht tun und zwar su folgendem Grund: Es gibt kaum Fälle in denen du in der 2. oder 3. Indirektion was mit der Exception anfangen kannst. Will heißen: entweder der direkte Aufrufer kann was damit anfangen oder die Exception sollte recht weit oben zentral behandelt werden.

Aber auch das ist Geschmackssache. Throws Deklarationen sind so unfachlich, so technisch, daher lass ich sie sobald wie möglich weg, schrei sie aber so lang wie nötig dran. ;)
Hab ich schon gemerkt dass es nicht so viel Sinn macht bzw dachte ich dass es so für mich übersichtlicher wird, jedoch macht es das ganze nur noch überladener - Fazit: Die Methode die eine Exception wirft, auch wenn es eine RE ist, bekommt ein throws in die Methodensignatur und Ende.


Finally wird immer ausgeführt, auch wenn eine Exception fliegt. Daher reicht es in dem Fall, den Aufräumcode im finally Block zu haben und die HibernateException einfach durchrauschen zu lassen - du brauchst also gar keinen Catchblock. Die HibernateException nochmal zu wrappen ist auch nicht so sehr schön. Das sorgt dann für eine (eigentlich unnötige) Indirektion mehr im Stacktrace.
ALLES KLAR!
 
Zuletzt bearbeitet:
Also heißt das dass ich meine IOException und FileNotFoundException bspw in eine BasisException für diese Art von Exception packen soll? Namensvorschlag für diesen Fall?^^
Wo soll ich jene dann am besten in die jeweilige BasisException wrappen? Damit es seine Ordnung hat bspw bei den Interface Implementation Methoden?
Wie wärs mit einer ${DeinProjekt}IOException? Wo? So zeitig wie möglich (siehe mein Vorschlag oben, die Exceptions direkt im Konstruktor zu fangen).

Klingt interessant, wie darf ich mir das vorstellen?
Im Falle von einem Webclient wäre z.B. ein Filter denkbar. Dann ginge sowas:

Java:
// Im Filter:

try {
  filterChain.proceed(..);
} catch (RuntimeException e) {
  exceptionTranslator.translate(e);
}

// Im Translator:

if (e instanceof $EineDeinerExceptions) {
  // Tu was sinnvolles
} else if (e instanceof $EineAndereDeinerExceptions) {
  // Tu noch was sinnvolles
} else {
  // Standardfall - sollte auch sinnvoll sein ;)
}

Den Filter ersetzt man im fortgeschrittenen Stadium durch einen ExceptionHandlingAspect an einem entsprechenden Pointcut.

Hab ich schon gemerkt dass es nicht so viel Sinn macht bzw dachte ich dass es so für mich übersichtlicher wird, jedoch macht es das ganze nur noch überladener - Fazit: Die Methode die eine Exception wirft, auch wenn es eine RE ist, bekommt ein throws in die Methodensignatur und Ende.

Das wichtige an Konventionen ist, dass man sie einhält. Das ist meist wichtiger, als, ob du dich für A oder B entscheidest. Von daher ist das ein guter Ansatz ;)
 
Zurück