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