JPA i walidacja: jak obsługiwać wyjątki?

0

Witam,
Piszę aplikacje bazodanową w EJB/JPA i JSF. Na jedna z kolumn nalozylem unikalny indeks po to, aby kontrolowac unikalnosc wpisywanych lancuchow znakow.

Chce wyswietlac rozne wiadomosci o bledach w zaleznosci od tego czy zlamanie zostanie jeden constraint (np. unikalnosc) lub drugi (np. ciag znakow jest za maly lub za dlugi). Myslalem o obsluzeniu tego za pomoca wyjatkow. Samo rzucenie wyjatku nie stanowi problemu: wystarczy sobie potworzyc puste klasy i uzywac slowa throw (no i nie zapomniec poinformowac o ich istnieniu interfejsy).

Powiedzmy przypadek z dlugoscia jest prosty:

  1. Dorabiam dodatkowe if, jesli cos jest za krotkie to rzucam wyjatek za krotki, jesli cos za dlugie to analogiczny inny wyjatek.

Pytanie: jak sprawdzic czy unikalnosc zostala zlamana? W logach to widze, dostaje dokladny komunikat.
org.postgresql.util.PSQLException

Czy musze lapac PSQLException w momencie dodawania i rzucac wlasny wyjatek czy tez da sie to zrobic elegancko? Samo PSQLE nie mowi za duzo o rodzaju naruszenia i to mnie najbardziej boli: tak do konca nie wiadomo co sie stalo.

Pozdrawiam,

1

Długość można walidować przez przekazaniem do JPA. Poszukaj informacji o Bean Validation. Jest to specka, w oparciu o którą implementowane są walidatory JPA. Błąd zwrócony przez BeanValidation jest dość klarowny i łatwy do obsłużenia. W dodatku obsługa następuje przed zabawą z SQLem zatem nie ma narzutu z zapytań.

Co do drugiego pytania. PSQLException dziedziczy po SQLException, a zatem ma metodę getErrorCode. Jak mówi dokumentacja kod błędu naruszenia więzów to 23505 (http://www.postgresql.org/docs/9.1/static/errcodes-appendix.html).

0

Tu masz przykładowy walidator JSF, którym możesz sprawdzić długość: http://www.mkyong.com/jsf2/custom-validator-in-jsf-2-0/

0

Dziękuje za zainteresowanie i wskazówki.

Olek1, nie chodzi mi o walidację na poziomie aplikacji internetowej, a na poziomie EJB. Czasem jest niezbędna np. przy użyciu WebServices.

Mój problem jest następujący: nie umiem złapać wyjątku w EJB (przy persist). Coś czytam, że potrzebny jest odpowiedni handler. Ale różne źródła nie są jednoznaczne. Używam EclipseLink, JPA 2.1, a

Widzę tylko komunikaty błędów w logach. Będę wdzięczny za wskazówki: mam poszalki, że potrzebuje złapać ConstraintViolatianException. Tylko gdzie..

0

Wiem, że to nie EclipseLink, ale ta hierarchia wyjatkow jest tym czego szukam.
http://www.objectdb.com/api/java/jpa/exceptions

Wciaz szukam rozwiazania, gdzie mozna je zlapac. Dodam, ze uzywam JTA.

0

Kurcze, jak malo rozumiem.

Ogolnie ustalilem, ze EJBException moge zlapac w aplikacji JSF (i wtedy wiem, ze wpis istnieje), ale nie gdy wykonuje persist na EntityManager. Nie do konca rozumiem dlaczego.

0

No to jest dosc proste - JPA nie wie nic na temat EJBException poniewaz nie ma z nim nic wspolnego (no ok, wywodzi sie poniekad ze specyfikacji ejb ale to dawne dzieje). EntityManager rzuca rozne wyjatki bedace podklasami PersistenceException, ktore, jesli ich sam nie lapiesz i nie obslugujesz, i uzywasz EJB, pakowane sa w EJBException itp. Ergo, jak chcesz obslugiwac bledy JPA to lap PersistenceException i inne podklasy.
Swoja droga, chyba nie jest takie trudne sprawdzenie jakie wyjatki rzuca EM? Nawet taki durny eclipse podpowiada w czasie pisania kodu jakie wyjatki rzuca dana metoda, to nie jest wielka filozofia.

0

Dzięki rozumiem coś więcej, ale jeszcze nie do końca.

Czemu ten kod nie łapie wyjątku skoro EnityManager rzuca PersistanceException?
http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html
Moj kod throw new CategoryExistsException() nie wykona sie.

0

Ehhh ze zmeczenia:

    @Override
    public void createCategory(Category category) throws CategoryExistsException {
        try {
            em.persist(category);
        } catch (PersistenceException e) {
            throw new CategoryExistsException();
        }
    }


0

Jesli EM rzuca PersistenceException to nie ma bata zeby ten kod sie nie wykonal. Wklej caly stack trace wyjatku ktory dostajesz ostatecznie (ten EJBException czy cokolwiek), pewnie ten twoj wyjatek gdzies tam w srodku jest ale opakowany przez 17 innych warstw. Czy ten twoj wyjatek jest Exception czy RuntimeException? (widze ze go podajesz w definicji metody ale to w sumie nic nie znaczy).

0

flush()

0

Dziekuje Szczery.

Taki kod lapie wyjatek:

    @Override
    public void createCategory(Category category) throws CategoryExistsException {
        try {
            em.persist(category);
            em.flush();
        } catch (PersistenceException e) {
            throw new CategoryExistsException();
        }
    }

Niesamowite. Podobna sytuacje mialem pracujac kiedys z gniazdami: poki nie wykonalem flush dane zwyczajnie nie trafialy do punktu docelowego.

Dlaczego em nie wykonuje flush automatycznie, wlasciwie czemu to ma sluzyc?

0

Bo masz pewnie domyslnie uzyte FlushModeType.AUTO. Juz teraz rozumiem dlaczego nie bylo wyjatku w tym miejscu, a byl pozniej - Javadoc metody persist() mowi miedzy innymi:

If the entity already exists, the EntityExistsException may be thrown when the persist operation is invoked, or the EntityExistsException or another PersistenceException may be thrown at flush or commit time.

Jako ze flush nie byl wolany przez twoj kod nigdzie, byl wolany przez kontener w momencie commita - czyli pdomyslnie po skonczeniu metody znanej przez kontener EJB ktora jest REQUIRES.

0

A czemu ma sluzyc? Flush kontaktuje sie z baza danych, wysyla wszystkie aktualnie zcachowane zaputania do bazu ktora costam robi. Jesli jest takich kontaktow za duzo, to aplikacja moze dzialac wolno. Dlatego jest furtka ze programista sam moze decydowac jak czesto flush jest wykonywany.

0

Sensowne. Dzieki za obszerne i rzeczowe wytlumaczenie.

1 użytkowników online, w tym zalogowanych: 0, gości: 1