Nie trzeba było długo czekać, a żeby mój poprzedni hack w XJC zmieniający importy dla silnie typizowanych kolekcji opisanych przez xjc:javaType a korzystających po stronie javy z adnotacji XmlAdapter okazał się niewystarczający i przyszła potrzeba kolejnego. Tym razem potrzeba wymusiła, aby w kolekcji znalazły się nie tylko typy z danego pakietu, czy też z pakietu java.lang.* ale klasa z innego pakietu.
Dopisanie jako typu wyjściowego adaptera np.
Map<String,pl.bedkowski.CustomClass>
kończyło się dodaniem do typu zwracanego przez metodę CustomClass> (tak znaczek większe „>” to nie pomyłka). No i znowu zacząłem przeglądać źródła, żeby znaleźć miejsce gdzie możnaby coś popsuć. Tym razem poszukiwania zaprowadziły mnie do klasy: com.sun.codeModel.jDirectClass, ktora wyraźnie nie jest przygotowana na przyjęcie silnie typizowanej kolekcji, a oto dlaczego:
private final String fullName;
public JDirectClass(JCodeModel _owner, String fullName) {
super(_owner);
this.fullName = fullName;
}
Jedyne co robi to przepisuje kwalifikowana nazwę do własności, a podczas pobieranie nazwy klasy zależy od pozycji ostatniej kropki w stringu, co wyjaśnia skąd w deklaracjach metod pojawiło się coś w stylu: CustomClass>. Teraz tylko trzeba ją jakoś przerobić, żeby obsługiwała typy własne.
To też nie okazało sie takie trudne jeżeli:
- pierwsze i najważniejsze – nie pragniesz sie skupić na pięknym rozwiązaniu a jedynie mieć coś co działa
- drugie – chcesz ubrudzić sobie troche rączki i zmniejszyć elastyczność rozwiązania o konieczność poadawania w pełni kwalifikowanej nazwy klasy (ale czy poprzedni punkt już tego nie zakłada
)
Jeżeli odpowiedzi na oba pytania są poprawne, to moje rozwiązanie wyglada tak:
- dodanie własności name
- sprawdzenie w konstruktorze przy pomocy wyrażenia regularnego czy klasa jest typizowana kolekcją (wiem fuuuj)
- ustawienie w zależności od tego atrybutu name, na nazwę sprzed znaku mniejszości <
- usunięcie reszty z nazwy
- no i jeszcze drobna modyfikacja metody name, tak żeby dało się pobrać nazwe kolekcji (klasy lub interfejsu)
A oto zmieniona część klasy:
final class JDirectClass extends JClass {
private final String fullName;
private final String name;
public JDirectClass(JCodeModel _owner, String fullName) {
super(_owner);
Pattern p = Pattern.compile("\\.(\\w+<.*?>)");
Matcher m = p.matcher(fullName);
if (m.find()) {
name = m.group(1);
this.fullName = fullName.replaceAll("<.*?>$", "");
} else {
name = null;
this.fullName = fullName;
}
}
public String name() {
if (name == null) {
int i = fullName.lastIndexOf(".");
if (i >= 0)
return fullName.substring(i + 1);
return fullName;
} else {
return name;
}
}
// reszta bez zmian
}
Leave a Reply