doanduyhai / Achilles

An advanced Java Object Mapper/Query DSL generator for Cassandra
http://achilles.archinnov.info
Apache License 2.0
241 stars 92 forks source link

DSL Generation - where-in clause for boolean (primitive) type field generation fails #312

Closed neuralcyst closed 7 years ago

neuralcyst commented 7 years ago

Hi,

I've met an error in generated methods for manager#dsl() - "where-in clauses" for column fields of primitive boolean type.

For this bean

@Table
public class MyEntity {
  @PartitioningKey
  int id;
  @ClusteringColumn
  @Column("boo_column")
  boolean booField;
  @ClusteringColumn(2)
  @Column("another_column")
  String anotherField;
  // getters and setters...
}

Achilles generates something like this:

/**
 * Generate a SELECT ... FROM ... WHERE ... <strong>boo_column IN ?</strong> */
 @SuppressWarnings("static-access")
 public final MyEntity_Select.W_AnotherField IN(boolean... booField) {
  Validator.validateTrue(ArrayUtils.isNotEmpty(booField), "Varargs for field '%s' should not be null/empty", "booField");
  where.and(QueryBuilder.in("boo_column",QueryBuilder.bindMarker("boo_column")));
  final List<Object> varargs = Arrays.<Object>asList((boolean[])booField);
  final List<Object> encodedVarargs = Arrays.stream((boolean[])booField).mapToObj(x -> meta.booField.encodeFromJava(x, Optional.of(cassandraOptions))).collect(Collectors.toList());
  boundValues.add(varargs);
  encodedValues.add(encodedVarargs);
  return new MyEntity_Select.W_AnotherField(where, cassandraOptions);
}

It contains error because there is no Arrays.stream() method for argument of boolean[] type.

Workaround exists - usage of "boxed" Boolean type for booField, but I gess this is a bug anyway, because primitives usage are preferable if it's possible.

My observations: Looks like I've found place responsible for this code generation - BaseSingleColumnRestriction#buildColumnInVarargs():

final $T encodedVarargs = $T.stream(($T[])$L).mapToObj(x -> meta.$L.encodeFromJava(x, $T.of(cassandraOptions))).collect($T.toList());

My proposal is to use standard for-loop instead of stream API. Something like that:

final $T encodedVarargs = new ArrayList<>($L.length);
for ($T x : inProgress) {
  encodedVarargs.add(meta.$L.encodeFromJava(x, $T.of(cassandraOptions)));
}

Best regards,

doanduyhai commented 7 years ago

Thanks for pointing out the bug. I definitely prefer the for() loop version!