[JAVA] tricky generics

Pagina: 1
Acties:

  • voodooless
  • Registratie: Januari 2002
  • Laatst online: 30-11 11:20

voodooless

Sound is no voodoo!

Topicstarter
Even als eerste vooraf: ja, ik weet dat Hibernate bestaat :+

Oke, wat ik dus gemaakt heb is een object abstractie van database tabellen. Je kunt dus direct objecten uit een database halen via een query of gewoon via ID. Tabelen en objecten worden aan de hand van annotations aan elkaar gekoppeld, en dat werkt ook heel erg netjes en snel tot nu toe.

Als er meer dan een Object uit komt wil ik een Iterator gebruiken. Echter moet deze iterator van een bepaalt type zijn, dus als we uit de database Kaas objecten halen, dan moet die Iterator<Kaas> zijn. En juist dat krijg ik niet voor elkaar zodat dat de compiler begint te zeuren over type safety.

That's where you come in, maw: hoe krijg ik dat voor elkaar?

Als eerste wat code, de Iterator:

Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class QueryItterator<T> implements Iterator{

        public ResultSet rs;
        public Class<T> obj;
        
        public QueryItterator(Class<T> obj,ResultSet rs){
            this.obj = obj;
            this.rs = rs;
        }
        
        public boolean hasNext() {
            try {
                return rs.next();
            } catch (SQLException e) {
                log.error("Exception:", e);
                return false;
            }
        }

        public T next() {
            try {
                return createObject(obj,rs);
            } catch (DAOException e) {
                log.error("Exception:", e);
                return null;
            } 
        }

        public void remove() {
            try {
                rs.deleteRow();
            } catch (SQLException e) {
                log.error("Exception:", e);
            }
        }
        
    }


En nu de code die de Iterator moet terug geven:

Java:
1
2
3
4
5
6
7
public <T extends Object> Iterator getByQuery(Class<T> obj, String tables,String whereClause,Object... values) throws DAOException {
        
                        .... knip ...

            ResultSet result = resultQuery( SQL query);
            return new QueryIterator(obj,result);
    }


Precies op die return geeft de compiler (of eigenlijk eclipse) dus die warning:
Type safety: The constructor GenericDAO.QueryIterator(Class, ResultSet) belongs to the
raw type GenericDAO.QueryIterator. References to generic type
GenericDAO.QueryIterator<T> should be parameterized
Ik heb al vanalles geprobeerd, maar het wil niet echt helpen. Het is natuurlijk wel slechts een warning, maar als je dit goed voor elkaar krijgt, scheelt, dat flink wat casting in de rest van de code :*)

Dus als jullie tips hebben: graag!

Ben dit weekeind niet echt beschikbaar achter de PC, dus reacties van mijn kant komen pas maandag weer :(

Do diamonds shine on the dark side of the moon :?


  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 07:54

Janoz

Moderator Devschuur®

!litemod

Moet je niet eerder in de richting kijken van:
Java:
1
return new QueryIterator<T>(obj,result);

en dan eigenlijk gewoon de obj parameter weglaten?

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • Marcj
  • Registratie: November 2000
  • Laatst online: 01-12 16:59
Al eerste kun je de QueryIterator<T> een Iterator<T> laten implementeren:

Java:
1
class QueryIterator<T> implements Iterator<T>


En dan vervolgens ook voor getByQuery dit doen:

Java:
1
2
3
4
5
6
public <T extends Object> Iterator<T> getByQuery(Class<T> obj,
            String tables, String whereClause, T... values)
            throws DAOException {
    ResultSet result = resultQuery("");
    return new QueryIterator<T>(obj, result);
}


volgens mij zou dit zo ongeveer moeten werken... maar is uiteraard niet getest

  • voodooless
  • Registratie: Januari 2002
  • Laatst online: 30-11 11:20

voodooless

Sound is no voodoo!

Topicstarter
Janoz schreef op vrijdag 20 april 2007 @ 17:29:
Moet je niet eerder in de richting kijken van:
Java:
1
return new QueryIterator<T>(obj,result);

en dan eigenlijk gewoon de obj parameter weglaten?
Klinkt interessant, maar hoe kan ik dan de Class van T benaderen? Want T.class of T.getClass of zelfs T meegeven in een functie aanroep werkt helaas niet. Zou wel interessant zijn om te weten hoe dat wel moet! En het is natuurlijk ook niet de oplossing voor het probleem ;)
Marcj schreef op vrijdag 20 april 2007 @ 18:28:
En dan vervolgens ook voor getByQuery dit doen:

Java:
1
    return new QueryIterator<T>(obj, result);
Dat is inderdaad de oplossing _/-\o_ . De eerste aanpassing (implements Iterator<T>) is niet eens nodig zo te zien, maar natuurlijk wel wat netter.

Zou mooi zijn als ik er nog achter kon komen hoe die inval van Janoz werkend te krijgen is though :)

* voodooless vindt dat Sun veel leuke dingen in java 5 heeft ingebakken. Op veel punten een verademing. Eerst denk je: ach, het zal wel allemaal, maar als je dan eindelijk over kunt en ermee aan de gang gaat vind je het toch als snel heel erg handig. Generics en Annotations rule :Y)

[ Voor 12% gewijzigd door voodooless op 23-04-2007 08:23 ]

Do diamonds shine on the dark side of the moon :?


  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

voodooless schreef op maandag 23 april 2007 @ 08:19:
Klinkt interessant, maar hoe kan ik dan de Class van T benaderen? Want T.class of T.getClass of zelfs T meegeven in een functie aanroep werkt helaas niet. Zou wel interessant zijn om te weten hoe dat wel moet! En het is natuurlijk ook niet de oplossing voor het probleem ;)
Daar is, voorzover ik heb kunnen bedenken/vinden, geen generieke oplossing voor. Een mogelijke oplossing is een abstracte methode getGenericClass aanmaken, die elke afgeleide klasse moet implementeren en die de klasse van de generic parameter teruggeeft. Smerig, maar effectief.

Je kan met behulp van reflection wel bij de generic klasse komen, maar dan moet je bijvoorbeeld weten in de hoeveelste generatie afgeleide klasse je zit en meer van zulke rotzooi. Dat soort code is erg breekbaar.

Wie trösten wir uns, die Mörder aller Mörder?


  • Marcj
  • Registratie: November 2000
  • Laatst online: 01-12 16:59
voodooless schreef op maandag 23 april 2007 @ 08:19:
[...]


Dat is inderdaad de oplossing _/-\o_ . De eerste aanpassing (implements Iterator<T>) is niet eens nodig zo te zien, maar natuurlijk wel wat netter.

Zou mooi zijn als ik er nog achter kon komen hoe die inval van Janoz werkend te krijgen is though :)

* voodooless vindt dat Sun veel leuke dingen in java 5 heeft ingebakken. Op veel punten een verademing. Eerst denk je: ach, het zal wel allemaal, maar als je dan eindelijk over kunt en ermee aan de gang gaat vind je het toch als snel heel erg handig. Generics en Annotations rule :Y)
Als je generics wilt gebruiken zou ik het ook overal gaan gebruiken. Als je het soms wel en soms niet doet, kun je een aantal hele lastige problemen tegen komen. Ik vind zelf dat deze tutorial generics wel goed uitlegd.

  • voodooless
  • Registratie: Januari 2002
  • Laatst online: 30-11 11:20

voodooless

Sound is no voodoo!

Topicstarter
Confusion schreef op maandag 23 april 2007 @ 08:33:
Daar is, voorzover ik heb kunnen bedenken/vinden, geen generieke oplossing voor. Een mogelijke oplossing is een abstracte methode getGenericClass aanmaken, die elke afgeleide klasse moet implementeren en die de klasse van de generic parameter teruggeeft. Smerig, maar effectief.
Met Generics wil je juist geen afgeleide klasse maken ;) Het zou wel werken natuurlijk, maar zoals gezegd, het is smerig, en je moet een afgeleide maken. Niet erg handig dus. Het is dan nog beter om de Class met de constructor mee te geven.

Ik ga eens kijken wat ik met reflection kan doen :)

Hier nog een leuke FAQ: http://www.angelikalanger...ns/ProgrammingIdioms.html , buiten de obvious dingen echter geen oplossing. Denk dat ik voorlopig nog maar blijf hangen op die constructor, werkt immers prima.

[ Voor 19% gewijzigd door voodooless op 23-04-2007 09:13 ]

Do diamonds shine on the dark side of the moon :?


Verwijderd

voodooless schreef op maandag 23 april 2007 @ 08:46:
Ik ga eens kijken wat ik met reflection kan doen :)
Generics omzeilen ;)

  • voodooless
  • Registratie: Januari 2002
  • Laatst online: 30-11 11:20

voodooless

Sound is no voodoo!

Topicstarter
-O-

Ik hoopte met reflection het runtime type van de generieke classe te kunnen achterhalen. Jammer maar helaas is me dat (nog) niet gelukt.

Do diamonds shine on the dark side of the moon :?


Verwijderd

voodooless schreef op maandag 23 april 2007 @ 10:16:
Ik hoopte met reflection het runtime type van de generieke classe te kunnen achterhalen. Jammer maar helaas is me dat (nog) niet gelukt.
Runtime is het niets anders dan een cast, je ziet er geloof ik ook neits van terug in de bytecode

  • Alex Picard
  • Registratie: November 2005
  • Laatst online: 19-11 00:56
Generics bestaan alleen voor de compiler om type-safety te enforcen... Vanwege compatibiliteit en performance bestaan generics niet at runtime, en worden generic aanroepen overal van typecasts voorzien.

De enige winst voor de programmeur is dat je minder fouten maakt door de strenge typecontrole en dat je niet steeds zelf je types hoeft te casten.

  • voodooless
  • Registratie: Januari 2002
  • Laatst online: 30-11 11:20

voodooless

Sound is no voodoo!

Topicstarter
Tja, dat dacht ik al. Erg jammer, want @ runtime zou je er ook nog leuke dingen mee kunnen doen :)

Do diamonds shine on the dark side of the moon :?


  • Salandur
  • Registratie: Mei 2003
  • Laatst online: 01-12 12:31

Salandur

Software Engineer

volgens mij heb je daar annotations voor

Assumptions are the mother of all fuck ups | iRacing Profiel


  • voodooless
  • Registratie: Januari 2002
  • Laatst online: 30-11 11:20

voodooless

Sound is no voodoo!

Topicstarter
Salandur schreef op maandag 23 april 2007 @ 10:51:
volgens mij heb je daar annotations voor
Nee, die zijn leuk voor andere dingen. Ik gebruik ze om aan te geven op welke tabel een object mapt en welke velden bij de getters en settere horen. Fun stuff :)

Wat ik nu juist wilde is die

Java:
1
public QueryIterator(Class<T> obj,ResultSet rs)


obj parameter vermeiden door direct T te gebruiken @ runtime, net als Janoz in zijn eerste reply voorstelt. Dat kun dus gewoon niet!

[ Voor 12% gewijzigd door voodooless op 23-04-2007 11:00 ]

Do diamonds shine on the dark side of the moon :?


  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 07:54

Janoz

Moderator Devschuur®

!litemod

Kun je niet gewoon:
Java:
1
public QueryIterator(T obj,ResultSet rs)

gebruiken en dan daarbinnen obj.getClass() aanroepen? Nadeel is dat je dan wel een instantie moet maken, maar dan hoef je niet met allerlij reflection aan de gang te gaan.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • voodooless
  • Registratie: Januari 2002
  • Laatst online: 30-11 11:20

voodooless

Sound is no voodoo!

Topicstarter
Die instantie wil ik juist niet aanmaken, want dat doet die createObject methode al voor me. Die iterator moet immers ook meerdere instantie van dat object aanmaken, vandaar dat ik ook enkel en alleen het type aangeef.

Je zegt dus gewoon tegen het DAO object dat je uit de database een berg Objecten dan type X wil, en de rest gaat vanzelf :)

Do diamonds shine on the dark side of the moon :?


  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 07:54

Janoz

Moderator Devschuur®

!litemod

Waar komt die createObject vandaan? Eventueel zou je die ook nog aan kunnen passen.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • voodooless
  • Registratie: Januari 2002
  • Laatst online: 30-11 11:20

voodooless

Sound is no voodoo!

Topicstarter
Die iterator is een inner class (ja, ugly, maar check maar eens wat Sun code, staat er vol mee ;) ), en createObject zorgt er dus voor dat het object aangemaakt wordt en gevuld wordt met de data uit de resultset.

Do diamonds shine on the dark side of the moon :?


Verwijderd

voodooless schreef op maandag 23 april 2007 @ 11:42:
Die iterator is een inner class (ja, ugly, maar check maar eens wat Sun code, staat er vol mee ;) )
Wat is er zo 'ugly' aan een dergelijke inner-class?

  • voodooless
  • Registratie: Januari 2002
  • Laatst online: 30-11 11:20

voodooless

Sound is no voodoo!

Topicstarter
Verwijderd schreef op maandag 23 april 2007 @ 13:07:
Wat is er zo 'ugly' aan een dergelijke inner-class?
Aan dergelijke dergelijke inner-classes is op zich niets ugly. Immers wil je van buiten ook niet zien welke iterator het ding terug geeft.

Do diamonds shine on the dark side of the moon :?


  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 07:54

Janoz

Moderator Devschuur®

!litemod

Zou je de source van createObject kunnen posten? Ik krijg namelijk een beetje het vermoeden dat dit probleem op een iets andere plek eleganter op te lossen is. (maar daarin kan ik het uiteraard mis hebben!)

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Verwijderd

voodooless schreef op maandag 23 april 2007 @ 13:13:
Aan dergelijke inner-classes is op zich niets ugly. Immers wil je van buiten ook niet zien welke iterator het ding terug geeft.
Moet het daarvoor dan een inner-class zijn om te verbergen welke implemenatie van een Iterator gebruikt wordt?

  • voodooless
  • Registratie: Januari 2002
  • Laatst online: 30-11 11:20

voodooless

Sound is no voodoo!

Topicstarter
Janoz schreef op maandag 23 april 2007 @ 13:16:
Zou je de source van createObject kunnen posten? Ik krijg namelijk een beetje het vermoeden dat dit probleem op een iets andere plek eleganter op te lossen is. (maar daarin kan ik het uiteraard mis hebben!)
Die code wil ik liever niet prijsgeven. Ik kan je wel vertellen waar het op neer komt:

- maak instantie van Object aan, constructor van het object hoort hierbij geen argumenten te hebben
- ga alle get methode langs en check hiervan de annotations op kolom namen die corresponderen met kolommen van de database tabel.
- indien kolom present, haal value (met correcte type natuurlijk) uit de ResultSet, en roep de corresponderende setter aan.
- return gevulde object

Op die manier vul ik dus mijn object met de waarde van de resultset. Ik han natuurlijk ook alle setters aflopen, maar dan krijg ik ergens anders in mijn code problemen. Ik heb er dus voor gekozen om de annotations bij de getters te zetten. Ik had ook de setters kunnen gebruiken natuurlijk. 't is om het even... Anyway, met flink wat caches is dit behoorlijk snel en merk je nagenoeg geen verschil in snelheid met het handmatig vullen objecten uit een recordset.
Verwijderd schreef op maandag 23 april 2007 @ 13:18:
Moet het daarvoor dan een inner-class zijn om te verbergen welke implemenatie van een Iterator gebruikt wordt?
Natuurlijk niet. Komt nog bij dat die iterator enkel en alleen door de betreffende outerklasse gebruikt wordt, ik zie dus geen rede waarom ik er een geen inner classe van zou maken.

[ Voor 14% gewijzigd door voodooless op 23-04-2007 13:25 ]

Do diamonds shine on the dark side of the moon :?


Verwijderd

voodooless schreef op maandag 23 april 2007 @ 13:23:
Natuurlijk niet. Komt nog bij dat die iterator enkel en alleen door de betreffende outerklasse gebruikt wordt, ik zie dus geen rede waarom ik er een geen inner classe van zou maken.
Nee ik zie ook geen reden waarom het niet een inner-class zou moeten kunnen mogen willen hebben zijn (off: leuke taal dat NL). Maar jij riep dat het 'ugly' was, dus ik vroeg me dan af wat je er op aan te merken had. Klaarblijkelijk dus niets :)

  • voodooless
  • Registratie: Januari 2002
  • Laatst online: 30-11 11:20

voodooless

Sound is no voodoo!

Topicstarter
Ik dit geval niet nee :P

Do diamonds shine on the dark side of the moon :?


  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 07:54

Janoz

Moderator Devschuur®

!litemod

Aangezien ik mezelf ook nog iets meer wil verdiepen in Generics ben ik eens ff wat met dit probleem wezen pielen. Ik heb iig de volgende link gevonden die handig zou kunnen zijn:

http://serdom.szn.pl/ser/...hout-using-class-literal/

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • voodooless
  • Registratie: Januari 2002
  • Laatst online: 30-11 11:20

voodooless

Sound is no voodoo!

Topicstarter
Dat soort dingen had ik ook al gevonden, maar hebben bij mij geen nut, aangezien het bovenliggende Object niet echt generiek is maar meerdere verschillende objecten kan uitspugen. Voor de iterator zou iets dergelijk nog kunnen, echter aangezien ik die Class toch al nodig heb ik bovenliggende object maatk het eigenlijk ook niet veel meer uit.

Do diamonds shine on the dark side of the moon :?


  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 07:54

Janoz

Moderator Devschuur®

!litemod

Als je de aanroep aanpast van obj naar obj.class ben je er in principe al. Het is inderdaad even een omweg, maar dan kun je het object vervolgens wel instantieren.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • voodooless
  • Registratie: Januari 2002
  • Laatst online: 30-11 11:20

voodooless

Sound is no voodoo!

Topicstarter
Ik werk toch ook steeds met de Class :? Of zie ik het nu fout?

Do diamonds shine on the dark side of the moon :?


  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 07:54

Janoz

Moderator Devschuur®

!litemod

Hmm, ik raak blijkbaar wat in de war omdat je obj gebruikt terwijl dat eigenlijk een class is (bij obj vermoed ik een instantie van ipv de class zelf)

maar dan zie ik het probleem even niet meer. Je kunt van een class toch gewoon getInstance() opvragen om hem te instantieren?

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • voodooless
  • Registratie: Januari 2002
  • Laatst online: 30-11 11:20

voodooless

Sound is no voodoo!

Topicstarter
Janoz schreef op maandag 23 april 2007 @ 14:43:
maar dan zie ik het probleem even niet meer. Je kunt van een class toch gewoon getInstance() opvragen om hem te instantieren?
Natuurlijk :) Daar lag het probleem ook niet :P (als je al over een probleem kon spreken). Het "probleem" lag bij de iterator die ik eventueel wat mooier wilde hebben. Maar dat gaat dus niet.

Do diamonds shine on the dark side of the moon :?

Pagina: 1