3

It's very common see a generic's DAO implementation like this:

public List<E> getResultList(String namedQuery, Map<String, Object> parameters) {
    Query query = entityManager.createNamedQuery(namedQuery);
    parameters.entrySet().forEach(e -> query.setParameter(e.getKey(), e.getValue()));
    return query.getResultList();
}

I have some problems with this approach:

  1. Using a complex structure to just pass a list of key & value data.
  2. Map creation is very verbose.

Example:

public List<TransacaoTEF> getActiveTransactions1(TipoMensagem tipoMensagem, LocalDate date) {
    Map<String, Object> parameters = new HashMap<>();
    parameters.put("type", tipoMensagem);
    parameters.put("date", date);
    return getResultList("namedQueryXTPO", parameters);
}

To avoid this I thought in create a simple Parameter class:

public List<E> getResultList(String namedQuery, Parameter... parameters) {
    Query query = entityManager.createNamedQuery(namedQuery);
    Arrays.stream(parameters).forEach(p -> query.setParameter(p.getName(), p.getValue()));
    return query.getResultList();
}

public List<E> getResultList(String namedQuery, List<Parameter> parameters) {
    Query query = entityManager.createNamedQuery(namedQuery);
    parameters.forEach(p -> query.setParameter(p.getName(), p.getValue()));
    return query.getResultList();
}   

Using:

public List<TransacaoTEF> getActiveTransactions2(TipoMensagem tipoMensagem, LocalDate date) {
    return getResultList("namedQueryXTPO", 
            new Parameter("type", tipoMensagem), new Parameter("date", date));
}

public List<TransacaoTEF> getActiveTransactions3(TipoMensagem tipoMensagem, LocalDate date) {
    List<Parameter> parameters = Arrays.asList(
            new Parameter("type", tipoMensagem), 
            new Parameter("date", date));
    return getResultList("namedQueryXTPO", parameters);
}   

It's over engineering or just paranoia ;p ?

Rodrigo Menezes
  • 340
  • 1
  • 4
  • 10

2 Answers2

1

It's over engineering or just paranoia ;p ?

I don't think it's either. Yes, a map is a generic data structure but it's also the first thing you reach out for when you need key-value or param-value pairs. So most people do it like that and then the rest of the code is just them being responsible and not do things like this:

Map<String, Object> parameters = new HashMap<>();
parameters.put(null, someValue);
parameters.put("%$@*^%", someOtherValue);

If you use a Parameter class you can do something extra than what a map gives you. You can assert or validate some of the things that you place inside it like not specifying a null parameter name like above, or maybe not send null values but a JDBC NULL instead, or whatever...

A map is just a bucket. What you put in is what you get out. Nothing fancy. If your application is simple, few disciplined developers, etc, then a map might be enough.

If you are building a library or if you want to make sure there are some safeties in place, then a Parameter class is better.

Bogdan
  • 3,600
  • 10
  • 13
1

To ease the tedium of creating the map I'll often write a little utility:. (skeleton code)

Map addKeyValuePairs(Map m, Object...pairs) {
   // TODO test that pairs has an even number
  for (int i=0; i<pairs.length; i+=2) {
     // TODO Add null checks as desired
     m.put(pairs[i].toString(), pairs[I+1].toString());
  }
  return m;
}
user949300
  • 8,679
  • 2
  • 26
  • 35