Archief - Java generics vraagje

Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.

passero

Legacy Member
Ik heb nog niet super veel met generic gewerkt. Heb al wat gezocht maar ik vind niet direct wat ik zoek...

Dit is wat ik heb:
Code:
public class Document{
   ...
}
public class SomeDocument extends Document {
   public void myMethod();
}

Nu heb ik ergens anders een klasse waar ik met het type Document wil werken maar waar ik tegelijkertijd die subklasse van wil gebruiken:

Code:
public class SomeClass {
   public <T extends Document> T getDocument(String id){
      Document d = new Document();
      return d;
   }

   public void doSomething(){
      SomeDocument d = this.getDocument();
      d.myMethod();
   }
}

Ik geloof dat ik dit vroeger al eens geprobeerd heb en dat ik toen de fout kreeg dat hij Document niet kon converteren naar SomeDocument.
Nu is de vraag, hetgeen ik hier geschreven heb qua code, is dat correct en zal dit werken? Als dit niet werkt, hoe moet ik dat dan oplossen?

Een ander vraagje en ik vermoed dat dit eerder syntax is. Stel dat ik een ArrayList wil teruggeven van <T extends Document>, hoe schrijf ik dat dan?
Normaal is het ArrayList<Document> maar hoe doe je dat met T extends Document?

(Ondertussen speel ik er ook wat mee dus het kan zijn dat ik ondertussen de oplossing vind, dan zal ik ook de thread updaten).

Gurdt

Legacy Member
Da weet idd nie naar wat die Document moet converteren. Dit is ergens ook logisch omdat die SomeDocument data nodig kan hebben. Die data kan onmogelijk zomaar ingevuld worden. Ge kunt dat oplossen door voor SomeDocument een constructor te definiëren waaraan ge een Document mee kunt geven. Die roept ge dan aan met als parameter this.getDocument().

Uw 2e issue, niet geprobeerd maar kan je dat niet gewoon zo teruggeven? Dus ArrayList<T extends Document>?

passero

Legacy Member
In mijn huidige implementatie heb ik dat idd opgelost door in de constructor de parent mee te geven maar dit wil zeggen dat ik dan alle getters/setters enzo moet overschrijven wat redelijk wat werk is als je veel child klasse hebt.
Dit is dus een constructie dat ik wil vermijden en ik dacht dit te kunnen oplossen met die generics.

Ik heb ondertussen volgende geprobeerd en dat lijkt te werken:

Code:
private <T extends Document> T getDocument(String name, Class c)
{
    Document d = (Document)c.newInstance(); 
    ....
     return d;
}

Hierop krijg ik dus een "incompatible type" error tijdens het compileren. Waarom kan ik hier geen document teruggeven?

Wat betreft de ArrayList, ik had die syntax al geprobeerd maar blijkt niet te werken.

Parnakra

Legacy Member
Als je dit soort constructies nodig hebt in plaats van gewoon een Document terug te geven, kan er wel eens iets niet kloppen aan je ontwerp.

passero

Legacy Member
Nu ge het zegt... Ik heb te ver zitten zoeken.
Blijkbaar als ik:
Code:
public AbstractDocument getDocument(String id,Class c){
    AbstractDocument d = (AbstractDocument)c.newInstance();
    return d;
}
public void test(){
    SomeDocument d = (SomeDocument)this.getDocument("1",SomeDocument.class);
    d.doSomeDocumentSpecificMethod();
}

Dit werkt dus :)
Geen ingewikkelde constructies nodig. Enkel die Class moet ik meegeven om een nieuwe instantie te kunnen maken van de klasse.

Misschien even de context schetsen van de vraag. Ik ben bezig met een API te schrijven voor een document management systeem. Het moet generic zijn dus ik weet niet op voorhand welke type Document er kunnen bestaan dus moet mijn framework flexibel zijn om ermee om te gaan.
Vandaar dat ik die extra constructie nodig heb om een specifieke instantie te maken.

NeverwinterX

Legacy Member
Nogal vreemd nog altijd.
Als de gebruiker dit doet met je framework:
Code:
public void test(){
    SomeDocument d = (SomeDocument)this.getDocument("1",SomeDocument.class);
    d.doSomeDocumentSpecificMethod();
}
Hij kan toch gewoon dit rechtstreeks doen:
Code:
public void test(){
    SomeDocument d = new SomeDocument();
    d.doSomeDocumentSpecificMethod();
}
Ik zie het nut niet van die extra getDocument methode (en die id trouwens, die wordt nu niet gebruikt). Definieer gewoon een klasse Document met de methodes die nodig zijn. In je framework zelf gebruik je dan overal gewoon Document. Laat potentiele gebruikers van het framework die maar subklassen wanneer nodig zoals een SomeDocument: die SomeDocument is dan ook een Document en kan even zeer meegegeven worden aan methodes die een Document verwachten. Ik heb de indruk dat je magisch alle verschillende acties die mensen toevoegen in subklassen ook wilt aanspreken in de superklasse, maar dat werkt natuurlijk niet, dat houdt geen steek.

passero

Legacy Member
Tuurlijk :)
Het was dan ook maar een voorbeeld om te omschrijven wat ik wil doen.
Die getDocument gaat in werkelijkheid de content server aanspreken en het document ophalen met zijn metadata. Die metadata zal hij dan in het document steken en teruggeven. Dit is de functie van die methode.

Het idee van mijn API is dat je het framework kan gebruiken om gemakkelijk de content server te gebruiken in een java app. In de content server kan je extra metadata velden toevoegen en kan je profielen (type documenten met groepen metadata) aanmaken.
In mijn framework voorzie ik dan annotation waarbij je kan zeggen welk attribuut gelinkt is aan welk metadataveld in de content server. In de getDocument method worden die metadatavelden gemapped op de attributen van de klasse van de gebruiker.

Mijn framework voorziet een basis Document klasse met de metadata van een vanilla install.
Je kan dan zelf die klasse extenden door gebruik te maken van annotations om zo uw eigen metadata te kunnen gebruiken enzo.

Hopelijk is dit een beetje duidelijker.

NeverwinterX

Legacy Member
passero zei:
Tuurlijk :)
Het was dan ook maar een voorbeeld om te omschrijven wat ik wil doen.
Die getDocument gaat in werkelijkheid de content server aanspreken en het document ophalen met zijn metadata. Die metadata zal hij dan in het document steken en teruggeven. Dit is de functie van die methode.

Het idee van mijn API is dat je het framework kan gebruiken om gemakkelijk de content server te gebruiken in een java app. In de content server kan je extra metadata velden toevoegen en kan je profielen (type documenten met groepen metadata) aanmaken.
In mijn framework voorzie ik dan annotation waarbij je kan zeggen welk attribuut gelinkt is aan welk metadataveld in de content server. In de getDocument method worden die metadatavelden gemapped op de attributen van de klasse van de gebruiker.

Mijn framework voorziet een basis Document klasse met de metadata van een vanilla install.
Je kan dan zelf die klasse extenden door gebruik te maken van annotations om zo uw eigen metadata te kunnen gebruiken enzo.

Hopelijk is dit een beetje duidelijker.

Maar de metadata is dus verschillend per subklasse van Document en je gaat die at-runtime moeten toekennen aan de juiste attributen van die subklasse? (Ervan uitgaande dat je niet al de metadata gewoon in een grote String pompt, maar dan zou je ook geen subklassen nodig hebben, dus dat zou niet veel steek houden.) Dan zul je toch een hoop reflection moeten bovenhalen.

Alternatief lijkt me om het Factory design pattern te gebruiken, als ik het plan toch goed begrijp althans. Mensen die Document willen subklassen bvb SomeDocument moeten dan ook DocumentCreator subklassen met bvb SomeDocumentCreator die dan het mappen van metadata naar attributen afhandelt voor SomeDocument.
Abstract factory pattern - Wikipedia, the free encyclopedia

passero

Legacy Member
De metadata is verschillend per subklasse maar heeft zowiezo de metadata van het basis Document type gemeen.

De reden waarom ik het op die manier wil ontwikkelen is omdat ik mijn inspiratie gehaald heb uit hibernate en jpa. Daar hoef je ook enkel wat informatie over de columns meegeven via annotation en de engine doet de rest. Je hoeft daar ook niet voor elke entiteit een eigen factory schrijven.
Dit princiepe wil ik dus ook bouwen.

Met reflection heb ik eigenlijk geen probleem. Als je weet dat andere frameworks zoals hibernate, jpa, EJB daar allemaal op gebasseerd zijn en toch deftige performantie kunnen leveren dan denk ik niet dat dit een bottleneck kan zijn. Zeker niet als je weet dat de API voor web applicaties zal dienen en dus wel op deftige servers moet draaien.
Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.
Terug
Bovenaan