2 votes

Java Generics & jOOQ - Comment créer un HashMap d'une colonne jOOQ vers une autre

J'ai une interface

public interface HistoryDao<B extends UpdatableRecord<B>, H extends UpdatableRecord<H>> extends TableDao<H>{
    default void saveHistoryForIds(List<Integer> ids) {
        HashMap<? extends TableField<H, ? extends TableField<H, ? extends Serializable>>, ? extends TableField<B, ? extends TableField<B, ? extends Serializable>>> mappings = setUpHistoryMapping();

        List<? extends TableField<H, ? extends Serializable>> tableFields = new ArrayList<>(mappings.keySet());

        ArrayList<H> hs = new ArrayList<>();
        jooq()
            .insertInto(table(), tableFields);

    }

    HashMap<? extends TableField<H, ? extends TableField<H, ? extends Serializable>>, ? extends TableField<B, ? extends TableField<B, ? extends Serializable>>> setUpHistoryMapping();
}

(TableDao est une interface mais ce n'est pas super important)

Et dans ma classe concrète, j'essaie d'implémenter

MyClassHere implements HistoryDao<ApprovalWorkflowRecord, ApprovalWorkflowHistoryRecord>

@Override
public HashMap<? extends TableField<ApprovalWorkflowHistoryRecord, ? extends TableField<ApprovalWorkflowHistoryRecord, ? extends Serializable>>, ? extends TableField<ApprovalWorkflowRecord, ? extends TableField<ApprovalWorkflowRecord, ? extends Serializable>>> setUpHistoryMapping() {
    HashMap<? extends TableField<ApprovalWorkflowHistoryRecord, ? extends TableField<ApprovalWorkflowHistoryRecord, ? extends Serializable>>, ? extends TableField<ApprovalWorkflowRecord, ? extends TableField<ApprovalWorkflowRecord, ? extends Serializable>>> x = new HashMap<>();

    TableField<ApprovalWorkflowHistoryRecord, Integer> id = APPROVAL_WORKFLOW_HISTORY.ID;

    x.put(id, APPROVAL_WORKFLOW.ID);
}

Je pense que mon problème a quelque chose à voir avec la covariance... (peut-être) mais je continue à obtenir cette erreur

x.put(id, APPROVAL_WORKFLOW.ID) ;

method Map.put(CAP#1,CAP#2) is not applicable
  (argument mismatch; TableField<ApprovalWorkflowHistoryRecord,Integer> cannot be converted to CAP#1)

method AbstractMap.put(CAP#1,CAP#2) is not applicable
  (argument mismatch; TableField<ApprovalWorkflowHistoryRecord,Integer> cannot be converted to CAP#1)

method HashMap.put(CAP#1,CAP#2) is not applicable
  (argument mismatch; TableField<ApprovalWorkflowHistoryRecord,Integer> cannot be converted to CAP#1)   where CAP#1,CAP#2 are fresh type-variables:
CAP#1 extends TableField<ApprovalWorkflowHistoryRecord,? extends TableField<ApprovalWorkflowHistoryRecord,? extends Serializable>> from capture of ? extends TableField<ApprovalWorkflowHistoryRecord,? extends TableField<ApprovalWorkflowHistoryRecord,? extends Serializable>> CAP#2 extends TableField<ApprovalWorkflowRecord,? extends TableField<ApprovalWorkflowRecord,? extends Serializable>> from capture of ? extends TableField<ApprovalWorkflowRecord,? extends TableField<ApprovalWorkflowRecord,? extends Serializable>>

7voto

Lukas Eder Points 48046

Si vous ignorez tout le bruit générique (certes impressionnant), votre problème se résume au problème classique de l'insertion d'une valeur dans une collection avec des caractères génériques :

Map<?, ?> x = new HashMap<>();
x.put("a", "b"); // Doesn't work.

Il suffit de supprimer tous les caractères génériques là où vous n'en avez pas besoin et de les remplacer par des types concrets. En règle générale :

  • Utilisez des caractères de remplacement dans les arguments des méthodes pour permettre aux appelants de méthodes de transmettre des collections moins spécifiques.
  • Utilisez des caractères de remplacement lorsque vous placez des types génériques dans des collections, par exemple List<Class<?>> ou dans ce cas List<TableField<H, ?>> .
  • Essayez d'éviter de renvoyer des caractères génériques dans les méthodes.

Voici comment résoudre ce problème dans votre cas :

public interface HistoryDao<
    B extends UpdatableRecord<B>, 
    H extends UpdatableRecord<H>
> extends TableDao<H> {
    default void saveHistoryForIds(List<Integer> ids) {
        HashMap<TableField<H, ?>, TableField<B, ?>> mappings = setUpHistoryMapping();
        List<TableField<H, ?>> tableFields = new ArrayList<>(mappings.keySet());
        jooq().insertInto(table(), tableFields);
    }

    HashMap<TableField<H, ?>, TableField<B, ?>> setUpHistoryMapping();
}

class MyClassHere implements HistoryDao<
    ApprovalWorkflowRecord, 
    ApprovalWorkflowHistoryRecord
> {

    @Override
    public HashMap<
        TableField<ApprovalWorkflowHistoryRecord, ?>, 
        TableField<ApprovalWorkflowRecord, ?>
    > setUpHistoryMapping() {
        HashMap<
            TableField<ApprovalWorkflowHistoryRecord, ?>, 
            TableField<ApprovalWorkflowRecord, ?>
        > x = new HashMap<>();

        x.put(APPROVAL_WORKFLOW_HISTORY.ID, APPROVAL_WORKFLOW.ID);
    }
}

Qu'est-ce que j'ai changé ?

  • Local Map n'utilisent plus de caractères génériques sur leurs clés/valeurs. Au lieu de Map<? extends TableField<...>, ? extends TableField<...>> écrivez simplement Map<TableField<...>, TableField<...>>
  • Il en va de même pour le setUpHistoryMapping() le type de retour de la méthode.
  • Vous n'avez pas besoin ? extends Serializable ici. Ce type de lien n'ajoute aucune valeur. Il suffit d'utiliser ? à la place.
  • Vous avez imbriqué TableField<?, TableField<...>> par accident. Cela n'a pas de sens dans un contexte de jOOQ.

Voir aussi :

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X