Skip to content

Commit

Permalink
ArC: improve runtime representation of array bean types
Browse files Browse the repository at this point in the history
Previously, we always used `GenericArrayType` to represent array
bean types at runtime. This is unexpected for people, and also
for at least one TCK test that expects a `java.lang.Class`
representation of `String[]`. This commit makes sure that arrays
of primitive types and simple class types are represented using
an array-typed `java.lang.Class` object.
  • Loading branch information
Ladicek committed Jan 30, 2023
1 parent ae91381 commit 1901563
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationTarget;
import org.jboss.jandex.AnnotationValue;
import org.jboss.jandex.ArrayType;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.FieldInfo;
Expand Down Expand Up @@ -186,13 +187,26 @@ private static void getTypeHandle(AssignableResultHandle variable, BytecodeCreat
getParameterizedType(variable, creator, tccl, type.asParameterizedType(), cache, typeVariables);

} else if (Kind.ARRAY.equals(type.kind())) {
Type componentType = type.asArrayType().component();
// E.g. String[] -> new GenericArrayTypeImpl(String.class)
AssignableResultHandle componentTypeHandle = creator.createVariable(Object.class);
getTypeHandle(componentTypeHandle, creator, componentType, tccl, cache, typeVariables);
ResultHandle arrayHandle = creator.newInstance(
MethodDescriptor.ofConstructor(GenericArrayTypeImpl.class, java.lang.reflect.Type.class),
componentTypeHandle);
ArrayType array = type.asArrayType();
Type elementType = array.component();
while (elementType.kind() == Kind.ARRAY) {
elementType = elementType.asArrayType().component();
}

ResultHandle arrayHandle;
if (elementType.kind() == Kind.PRIMITIVE || elementType.kind() == Kind.CLASS) {
// can produce a java.lang.Class representation of the array type
// E.g. String[] -> String[].class
arrayHandle = doLoadClass(creator, array.name().toString(), tccl);
} else {
// E.g. List<String>[] -> new GenericArrayTypeImpl(new ParameterizedTypeImpl(List.class, String.class))
Type componentType = type.asArrayType().component();
AssignableResultHandle componentTypeHandle = creator.createVariable(Object.class);
getTypeHandle(componentTypeHandle, creator, componentType, tccl, cache, typeVariables);
arrayHandle = creator.newInstance(
MethodDescriptor.ofConstructor(GenericArrayTypeImpl.class, java.lang.reflect.Type.class),
componentTypeHandle);
}
if (cache != null) {
cache.put(type, arrayHandle, creator);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package io.quarkus.arc.test.bean.types;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.lang.reflect.Type;
import java.util.List;
import java.util.Set;

import javax.enterprise.context.Dependent;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.util.TypeLiteral;
import javax.inject.Named;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.arc.Arc;
import io.quarkus.arc.InjectableBean;
import io.quarkus.arc.test.ArcTestContainer;

public class ArrayBeanTypesTest {
@RegisterExtension
ArcTestContainer container = new ArcTestContainer(Producer.class);

@Test
public <T> void test() {
InjectableBean<Object> intArray = Arc.container().instance("intArray").getBean();
assertBeanTypes(intArray, Object.class, int[][].class);

InjectableBean<Object> stringArray = Arc.container().instance("stringArray").getBean();
assertBeanTypes(stringArray, Object.class, String[].class);

InjectableBean<Object> listArray = Arc.container().instance("listArray").getBean();
assertBeanTypes(listArray, Object.class, new TypeLiteral<List<String>[]>() {
}.getType());
}

private void assertBeanTypes(Bean<?> bean, Type... expectedTypes) {
Set<Type> types = bean.getTypes();

assertEquals(expectedTypes.length, types.size());
for (Type expectedType : expectedTypes) {
assertTrue(types.contains(expectedType));
}
}

@Dependent
static class Producer<T extends Number> {
@Produces
@Dependent
@Named("intArray")
int[][] intArray() {
return new int[0][0];
}

@Produces
@Dependent
@Named("stringArray")
String[] stringArray() {
return new String[0];
}

@Produces
@Dependent
@Named("listArray")
List<String>[] listArray() {
return (List<String>[]) new List<?>[0];
}
}
}

0 comments on commit 1901563

Please sign in to comment.