From 92b978bda96330e7f16aeee8693e9d823b4f8343 Mon Sep 17 00:00:00 2001 From: Ruben Dijkstra Date: Sat, 12 Apr 2014 01:00:50 +0200 Subject: [PATCH] Replaced System.arraycopy with reflective array access. This solves ArrayStoreExceptions that would otherwise occur with a primitive array. --- .../mysema/query/util/ConstructorUtils.java | 29 +++++++---- .../mysema/query/types/ProjectionExample.java | 13 +++-- .../mysema/query/types/ProjectionsTest.java | 48 +++++++++++-------- 3 files changed, 59 insertions(+), 31 deletions(-) diff --git a/querydsl-core/src/main/java/com/mysema/query/util/ConstructorUtils.java b/querydsl-core/src/main/java/com/mysema/query/util/ConstructorUtils.java index e78f20273..7a56d244d 100644 --- a/querydsl-core/src/main/java/com/mysema/query/util/ConstructorUtils.java +++ b/querydsl-core/src/main/java/com/mysema/query/util/ConstructorUtils.java @@ -166,13 +166,19 @@ public class ConstructorUtils { private static class VarArgsTransformer extends ConstructorArgumentTransformer { - private Class[] paramtypes; + private final Class[] paramTypes; + private final Class componentType; private VarArgsTransformer(Constructor constructor) { super(constructor); - paramtypes = constructor.getParameterTypes(); + paramTypes = constructor.getParameterTypes(); + if (paramTypes.length > 0) { + componentType = paramTypes[paramTypes.length - 1].getComponentType(); + } else { + componentType = null; + } } @Override @@ -182,16 +188,23 @@ public class ConstructorUtils { @Override public Object[] apply(Object[] args) { - Class[] paramTypes = constructor.getParameterTypes(); + Iterator iterator = Arrays + .asList(args) + .iterator(); + // constructor args Object[] cargs = new Object[paramTypes.length]; - System.arraycopy(args, 0, cargs, 0, cargs.length - 1); + for (int i = 0; i < cargs.length - 1; i++) { + Array.set(cargs, i, iterator.next()); + } // array with vargs int size = args.length - cargs.length + 1; - Object[] array = (Object[]) Array.newInstance( - paramTypes[paramTypes.length - 1].getComponentType(), size); - cargs[cargs.length - 1] = array; - System.arraycopy(args, cargs.length - 1, array, 0, size); + Object vargs = Array.newInstance( + componentType, size); + cargs[cargs.length - 1] = vargs; + for (int i = 0; i < Array.getLength(vargs); i++) { + Array.set(vargs, i, iterator.next()); + } return cargs; } diff --git a/querydsl-core/src/test/java/com/mysema/query/types/ProjectionExample.java b/querydsl-core/src/test/java/com/mysema/query/types/ProjectionExample.java index 108b5c448..85a671186 100644 --- a/querydsl-core/src/test/java/com/mysema/query/types/ProjectionExample.java +++ b/querydsl-core/src/test/java/com/mysema/query/types/ProjectionExample.java @@ -13,12 +13,12 @@ */ package com.mysema.query.types; -public class ProjectionExample{ +public class ProjectionExample { public Long id; - + public String text; - + public ProjectionExample() { } @@ -43,4 +43,9 @@ public class ProjectionExample{ } -} \ No newline at end of file + public ProjectionExample(Long id, char... characters) { + this.id = id; + this.text = String.copyValueOf(characters); + } + +} diff --git a/querydsl-core/src/test/java/com/mysema/query/types/ProjectionsTest.java b/querydsl-core/src/test/java/com/mysema/query/types/ProjectionsTest.java index 47558685c..d0721027b 100644 --- a/querydsl-core/src/test/java/com/mysema/query/types/ProjectionsTest.java +++ b/querydsl-core/src/test/java/com/mysema/query/types/ProjectionsTest.java @@ -23,41 +23,41 @@ import com.mysema.query.types.path.PathBuilder; public class ProjectionsTest { public static class VarArgs { - + String[] args; - + public VarArgs(String... strs) { args = strs; } } - + public static class VarArgs2 { - + String arg; String[] args; - + public VarArgs2(String s, String... strs) { arg = s; args = strs; } } - + @SuppressWarnings("unchecked") @Test public void Array() { - FactoryExpression expr = Projections.array(String[].class, + FactoryExpression expr = Projections.array(String[].class, new PathImpl(String.class, "p1"), new PathImpl(String.class, "p2")); - assertEquals(String[].class, expr.newInstance("1","2").getClass()); + assertEquals(String[].class, expr.newInstance("1", "2").getClass()); } @Test public void BeanClassOfTExpressionOfQArray() { PathBuilder entity = new PathBuilder(Entity.class, "entity"); QBean beanProjection = Projections.bean(Entity.class, - entity.getNumber("cId",Integer.class), + entity.getNumber("cId", Integer.class), entity.getNumber("eId", Integer.class)); - assertEquals(Entity.class, beanProjection.newInstance(1,2).getClass()); + assertEquals(Entity.class, beanProjection.newInstance(1, 2).getClass()); } @Test @@ -65,33 +65,43 @@ public class ProjectionsTest { Expression longVal = ConstantImpl.create(1l); Expression stringVal = ConstantImpl.create(""); assertEquals(ProjectionExample.class, Projections.constructor(ProjectionExample.class, longVal, stringVal) - .newInstance(0l,"").getClass()); + .newInstance(0l, "").getClass()); } - + @Test public void Constructor_VarArgs() { Expression stringVal = ConstantImpl.create(""); - VarArgs instance = Projections.constructor(VarArgs.class, stringVal).newInstance("X", "Y"); - assertArrayEquals(new String[]{"X", "Y"}, instance.args); + VarArgs instance = Projections.constructor(VarArgs.class, stringVal, stringVal).newInstance("X", "Y"); + assertArrayEquals(new String[]{"X", "Y"}, instance.args); } - + @Test public void Constructor_VarArgs2() { Expression stringVal = ConstantImpl.create(""); VarArgs2 instance = Projections.constructor(VarArgs2.class, stringVal, stringVal, stringVal).newInstance("X", "Y", "Z"); assertEquals("X", instance.arg); - assertArrayEquals(new String[]{"Y", "Z"}, instance.args); + assertArrayEquals(new String[]{"Y", "Z"}, instance.args); + } + + @Test + public void Constructor_VarArgs3() { + Constant longVal = ConstantImpl.create(1L); + Constant charVal = ConstantImpl.create('\0'); + ProjectionExample instance = Projections + .constructor(ProjectionExample.class, longVal, charVal, charVal, charVal, charVal, charVal, charVal) + .newInstance(1L, 'm', 'y', 's', 'e', 'm', 'a'); + assertEquals(1L, (long) instance.id); + assertEquals("mysema", instance.text); } @Test public void FieldsClassOfTExpressionOfQArray() { PathBuilder entity = new PathBuilder(Entity.class, "entity"); QBean beanProjection = Projections.fields(Entity.class, - entity.getNumber("cId",Integer.class), + entity.getNumber("cId", Integer.class), entity.getNumber("eId", Integer.class)); - assertEquals(Entity.class, beanProjection.newInstance(1,2).getClass()); + assertEquals(Entity.class, beanProjection.newInstance(1, 2).getClass()); } - }