ArrayIndexOutOfBoundsException when using FactoryExpressionBase.skipNulls() #1496

pvcastro opened this Issue Aug 24, 2015 · 18 comments


None yet

5 participants


I have the following code:

public class Credenciamento {

    public Credenciamento(Long id, LocalDate dataCriacao, LocalDate dataFim, InstituicaoCredora instituicaoCredora, Binario binario) { = id;
        this.dataCriacao = dataCriacao;
        this.dataFim = dataFim;
        this.instituicaoCredora = instituicaoCredora;
        this.binario = binario;


public Credenciamento consultar(Credenciamento credenciamentoPesquisa) {
        return newQuery()//
                .select(QCredenciamento.create(, credenciamento.dataCriacao, credenciamento.dataFim, //
                        instituicaoCredora, //
                        QBinario.create(, binario.contentType, //
                                QArmazemDeBinario.create(, armazemDeBinario.caminho).skipNulls())//
                .join(credenciamento.instituicaoCredora, instituicaoCredora)//
                .leftJoin(credenciamento.binario, binario)//
                .leftJoin(binario.armazem, armazemDeBinario)//

I'm trying to use the skipNulls method from the FactoryExpression class because I'm always getting empty classes when using a projected query and when leftJoin doesn't have an association in the database.

In the example above, a "Credenciamento" search performs a leftJoin with "Binario", but when there isn't any associated Binario in the database, instead of getting a null Binario passed to Credenciamento, I'm getting an instantiated Binario with empty attributes (the associated ArmazemDeBinario inside Binario is also empty instead of null).

I'm trying to use skipNulls like in my consultar method above, and I'm getting an ArrayIndexOutOfBoundsException in the following method from ArrayUtils.

I'm using QueryDSL 4.0.1.

// copied and modified from commons-lang-2.3
    // originally licensed under ASL 2.0
    public static Object[] subarray(Object[] array, int startIndexInclusive, int endIndexExclusive) {
        int newSize = endIndexExclusive - startIndexInclusive;
        Class<?> type = array.getClass().getComponentType();
        if (newSize <= 0) {
            return (Object[]) Array.newInstance(type, 0);
        Object[] subarray = (Object[]) Array.newInstance(type, newSize);
        System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);
        return subarray;


at java.lang.System.arraycopy(Native Method)
at com.querydsl.core.util.ArrayUtils.subarray(
at com.querydsl.core.types.FactoryExpressionUtils.compress(
at com.querydsl.core.types.FactoryExpressionUtils.access$100(
at com.querydsl.core.types.FactoryExpressionUtils$FactoryExpressionAdapter.newInstance(
at com.querydsl.jpa.FactoryExpressionTransformer.transformTuple(
at org.hibernate.hql.internal.HolderInstantiator.instantiate(
at org.hibernate.loader.hql.QueryLoader.getResultList(
at org.hibernate.loader.Loader.listIgnoreQueryCache(
at org.hibernate.loader.Loader.list(
at org.hibernate.loader.hql.QueryLoader.list(
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(
at org.hibernate.engine.query.spi.HQLQueryPlan.performList(
at org.hibernate.internal.SessionImpl.list(
at org.hibernate.internal.QueryImpl.list(
at org.hibernate.internal.AbstractQueryImpl.uniqueResult(
at com.querydsl.jpa.hibernate.AbstractHibernateQuery.fetchOne(


Could you maybe use code fences?

// code here

Is this ok?


Yes thank you, this is much better than manually counting parentheses.


Just for the record, I have experienced the same issue with the following code:

                .join(foxtrotInvoice.externalCompany, foxtrotExternalCompany)
                .join(, foxtrotCompany)
                .groupBy(, foxtrotCompany.creditLimit, foxtrotCompany.delphi, foxtrotCompany.experianDbt)

There is something fishy going on in FactoryExpressionTransformer.transformTuple(Object[], String[])
It starts with a tuple of Long, BigDecimal, BigDecimal, BigDecimal and instead of turning it into a Tuple of Long,Book(BigDecimal, BigDecimal, BigDecimal) it is turning it into a tuple of Long,BigDecimal simply truncating the last two fields. I am running version 3.6.6, but the same behaviour happens with 4.0.3


What happens here: com.querydsl.jpa.FactoryExpressionTransformer.transformTuple( How big is the tuple array?


The incoming Object[] = {Long, BigDecimal}, so it's size 2.
The incoming alias[] = {"0", "1", "2", "3"}
Notice I'm trying to return a Map<Long, Book> where Book is created from 3 BigDecimals via QBook.create().


Thanks. And what about @pvcastro?


My tuple array at this point is size 5, but the last element is null.


Please consider the edit in my reply above. I was answering from memory and just now reverted the code to properly debug it.


I did not manage to replicate the issue in the PR. Could you take a look? Or maybe provide a minimal example that has the same error?


Hi @timowest , are you asking me or @pedro-borges ?




You could try a projected query left-joining another entity, with no result found for the association:

public class Entity1 {

    private Entity2 entity2;

    public Entity (Long id, Entity2 entity2) { = id;
        this.entity2 = entity2;


public class Entity2 {

    public Entity2 (Long id) { = id;


public Entity1 find() {
        QEntity1 entity1 = QEntity1.entity1;
        QEntity2 entity2 = QEntity2.entity2;
        return new HibernateQuery<Entity1>(getSession())//
                .select(QEntity1.create(, QEntity2.create(
                .leftJoin(entity1.entity2, entity2)//

Try the code above, with a row contaning a null value for entity2 in the Entity1 table.
With skipNulls I get the ArrayIndexOutOfBoundsException, and without I get an empty Entity2.


Sorry for not replying on time, I believe the issue has been isolated and solved by now.
Will there be an update on this page stating the release this changes will come out in?

Thanks, keep up the great work


This fix should be part of the release that's being made today.

@Shredder121 Shredder121 closed this in #1497 Aug 31, 2015
@timowest timowest added this to the 4.0.4 milestone Aug 31, 2015
@timowest timowest removed the progress label Aug 31, 2015
pvcastro commented Sep 4, 2015

Great job! Thanks for the fix!
I have a question though. Shouldn't this "skipNulls" be the default behavior? If you don't find a particular joined association, shouldn't it be null without having to explicitly specify it?

timowest commented Sep 7, 2015

For backwards compatibility skipNulls is not the default. Also with multiple independent bindings to a projection, skipNulls might not always be the expected behaviour.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment