Erfaringer med Maven, Toplink, Swing, JPA og diverse :)
by arnljot on Jun.16, 2008, under java
Den 5. mai begynte jeg hos ny kunde. Et spennende prosjekt som relaterer seg til produksjonsstyring. Her skal vi skrive en fet klient som gjør alle sine tunge operasjoner på en OAS server vha EJB3.0 Session Beans.
Erfaringer:
1) @MappedSuperclass i javax.persistence 1.0 kan ikke inngå i relasjoner!
Denne var ikke uten videre innlysende for meg, og heller ingen andre på prosjektet her. Men vi skjønnte tidlig at det måtte være dette som var feil. Tilslutt fant vi et quote på en webside som vi tolket dithen at vi ikke kunne bruke det slik vi tenkte. Fra siden http://en.wikibooks.org/wiki/Java_Persistence/Inheritance#Mapped_Superclasses leser man følgende: “It is similar to table per class inheritance, but does not allow querying, persisting, or relationships to the superclass“. Dette klarte vi ikke å finne i API spesifikasjonen http://java.sun.com/javaee/5/docs/api/javax/persistence/MappedSuperclass.html eller fra bøkene OReily boken om JPA eller PRO EJB 3 JPA API.
2) Maven plugin maven-plugin-plugin har en bug som ikke tillater 1.5 annotations eller andre 1.5 source features i plugins kode.
Denne var værre å forstå. Helt til man dypt inne i Maven dokumentasjonen finner at maven ikke er 1.5 compliant i sin core ennå. Og at plugins kompileres med noe som heter QDox som kjører en Java extractor. Denne extractoren er java 1.4 kompliant.
Maven utviklerne har bestemt seg for å unngå problemet ved å avvise alle feil av denne typen, og heller velge å si at pluginkode må være java 1.4, og at de heller legger til en excludesources feature til maven-plugin-plugn slik at man får bygget pluginprosjekter som benytter seg av java 1.5 features.
For de som vil føge saken er issuen med avgjørelsen her: http://jira.codehaus.org/browse/MPLUGIN-15, og den opprinnelige feilen vi fant er MPLUGIN-21 og MPLUGIN-1 (man legger ikke inn en issue ticket uten å undersøke om de finnes fra før
)
3) JDeveloper kompilere generics klasser hvor inline klasser benytter seg av instanceof
Denne er morsom. Pseudokode:
/**
* Demonstrates a bug in the maven compiler
*
* @author <a href=”mailto:NOSPAM_arnljot.arntsen[at]avenir[dot]no_NOSPAM”>Arnljot Arntsen</a>
*/
public class MavenFailToCompile<T> {
class InlineClass {public boolean equals(Object o) {
if(o == null) { return false;}
if(!(o instanceof InlineClass)) { return false;}
// This will compile:
// if(o.getClass().equals(InlineClass.class)) { return true;}
if(o == this) {return true;}return super.equals(o);
}
}
}
Feilen man får er:
C:\code\mvn-compile-bug\src\main\java\MavenFailToCompile.java:[11,21] illegal generic type for instanceof
JDeveloper, har altså en bug som ikke Maven eller JavaC har. Først trodde vi det var andre veien. Men etter å ha dobbelt sjekket spes for generics og JavaC. Så er det Maven som har rett, og JDeveloper som gjør feil når den klarer å lage klassefiler av denne koden.
4) Toplink essentials støtter ikke orphan, toplink essentials støtter ikke ophans
Dette er mest et hjertesukk enn noe mer. Vi hadde ikke forutsett alle problemene vi skulle få med relasjoner gitt problemer med entitymanager.merge(entity) og det at frakoblede objekter hvor alt av relasjoner er nullet ut IKKE blir tatt livet av. I Hibernate når det er din JPA provider så løser man det så lekkert med CascadeType.DELETE_ORPHAN. Det er noe vi alle tar forgitt mange ganger…
Toplink/Toplink-essentials har sitt tilsvar, men er ikke noe særlig lekkert:
Man legger til i persistence.xml en toplink spesifik attributt, som tilpasser sesjonene… (ex name=toplink.session.customizer value=mypackage.PrivateOwnedCustomizer)
package mypackage;
import oracle.toplink.essentials.sessions.Session;
import oracle.toplink.essentials.mappings.OneToManyMapping;
/**
* PUBLIC:
* This interface is to allow extra customization on a TopLink Session
*/public class PrivateOwnedCustomizer extends SessionCustomizer {
public void customize(Session session) throws Exception {
RelationalDescriptor entityDescriptor = (RelationalDescriptor) session.getDescriptor(domainmodel.MyEntity.class);
OneToManyMapping mapping = (OneToManyMapping)entityDescriptor.getMappingForAttributeName(”<propertyName>”);
mapping.privateOwnedRelationship();
}
}
Som dere ser blir dette en svært mer intrengende endring enn en egen Hibernate mapping (org.hibernate.annotations.CascadeType.DELETE_ORPHAN).
Vi har da heller valgt å løseutfordringen den standard JPA måten, uten fancy hjelp fra Hibernate, og følger det PRO EJB 3 boken og JPA spesifikasjonen repeterer igjen og igjen:
Relationship maintenance is the responsibility of the applicatiobn. We are going to repeat this statement over the course of this book, but it cannot be emphasized enough. Almost every problem related to removing an entity always comes back to this issue.
Konsekvensen for oss gitt denne forskjellen mellom “Standard JPA” og “Hibernate JPA” er at våre bønners metoder for å oppdattere entiteter i databasen blir vesentlig mye mer verbos…
5) SwingX har noen bugs…
Ofte har “problemer” i data modeller skyldtes bugs i SwingX sin render pipeline og eventhandling. Feks SwingX issue #855.
6) JDeveloper sin POJO generator gjør et slett arbeid…
equals(), toString() og hashCode() mangler som oftes. Vilket fører til at bugs du opplever i applikasjonen først ikke virker opplagte… Men når du tar en titt på equals() og hashCode() så skjønner du raskt hvorfor…
7) Elementers rekkefølge i Maven POM er ikke likegyldig.
Sørg for at alle Managment seksjoner står før Plugin eller dependency seksjoner. Og definer properties først, selv om POM userguide sier noe annet. OG definer parent så tidlig som mulig, også dette på tværs av POM userguide anbefalninger. Gjør du dette så vil du unngå mange rare problemer.
Dependency management…
Det er kanskje opplagt for alle at <type> er en del av “nøkkelen” til det som ligger i DependencyManagement. Vel, det er det.
9) oc4jClient.jar er et mareritt å “mavenize”
Men det lar seg gjøre på noen timer, og med tunga rett i munnen….
10) Timbuktu prosjektet på Apache (mange oracle utviklere der…)
Timbuktu prosjektet har en plugin som lar deg lage et JDeveloper prosjekt av et maven prosjekt… Virker ok nok.
—
Der har vært mange andre små finurligheter. Som feks at det er lett å glemme og konfigurere opp maven-ear-plugin med rett JavaEE versjon når man skal bruke EJB3.0… I mellomstort prosjekt som det vi har (22 pom filer, 4 pom aggregerings prosjekter - super, server, plugins, maven), så er det utrolig viktig og tidlig få en god struktur og unngå sirkel-avhengigheter mellom prosjektene.
==> Det er vanskelig å mavenize en JDeveloper “prototype”.
—
Spørsmål vi ikke har fullgode svar på ennå:
1) Hvordan skal vi teste bønnene våre?
Vi hadde opprinnelig valgt EJB3Unit her. Men pga en bug i Hibernate som den test-harnessen er avhengig av så kan vi ikke bruke det (noe sånn som “lazy: cannot fetch more than one bag at a time”). Vi kan bruke JMock, TestNG etc etc… Men vi ønsket oss en test som også loaded persistence.jar fila vår og verifiserte spørringer etc.
2) Hvordan skal vi teste Swing GUI
Vi holder på å teste ut UISpec4J. Så langt så virker det svært lovende.
3) Hvorfor henger Hudson seg når den skal bygge maven prosjektet vårt
Heldigvis er vi ikke alene om denne bugen, og Hudson teamet har releaset en ny versjon av Hudson som lar deg se på mavens minne mens den byger (stack) slik at du kan hjelpe dem i å finne ut av det…