use of io.quarkus.builder.item.SimpleBuildItem in project quarkus by quarkusio.
the class ExtensionLoader method loadStepsFromClass.
/**
* Load all the build steps from the given class.
*
* @param clazz the class to load from (must not be {@code null})
* @param readResult the build time configuration read result (must not be {@code null})
* @param runTimeProxies the map of run time proxy objects to populate for recorders (must not be {@code null})
* @return a consumer which adds the steps to the given chain builder
*/
private static Consumer<BuildChainBuilder> loadStepsFromClass(Class<?> clazz, BuildTimeConfigurationReader.ReadResult readResult, Map<Class<?>, Object> runTimeProxies, BooleanSupplierFactoryBuildItem supplierFactory) {
final Constructor<?>[] constructors = clazz.getDeclaredConstructors();
// this is the chain configuration that will contain all steps on this class and be returned
Consumer<BuildChainBuilder> chainConfig = Functions.discardingConsumer();
if (Modifier.isAbstract(clazz.getModifiers())) {
return chainConfig;
}
// this is the step configuration that applies to all steps on this class
Consumer<BuildStepBuilder> stepConfig = Functions.discardingConsumer();
// this is the build step instance setup that applies to all steps on this class
BiConsumer<BuildContext, Object> stepInstanceSetup = Functions.discardingBiConsumer();
if (constructors.length != 1) {
throw reportError(clazz, "Build step classes must have exactly one constructor");
}
EnumSet<ConfigPhase> consumingConfigPhases = EnumSet.noneOf(ConfigPhase.class);
final Constructor<?> constructor = constructors[0];
if (!(Modifier.isPublic(constructor.getModifiers())))
constructor.setAccessible(true);
final Parameter[] ctorParameters = constructor.getParameters();
final List<Function<BuildContext, Object>> ctorParamFns;
if (ctorParameters.length == 0) {
ctorParamFns = Collections.emptyList();
} else {
ctorParamFns = new ArrayList<>(ctorParameters.length);
for (Parameter parameter : ctorParameters) {
Type parameterType = parameter.getParameterizedType();
final Class<?> parameterClass = parameter.getType();
final boolean weak = parameter.isAnnotationPresent(Weak.class);
final boolean overridable = parameter.isAnnotationPresent(Overridable.class);
if (rawTypeExtends(parameterType, SimpleBuildItem.class)) {
final Class<? extends SimpleBuildItem> buildItemClass = rawTypeOf(parameterType).asSubclass(SimpleBuildItem.class);
stepConfig = stepConfig.andThen(bsb -> bsb.consumes(buildItemClass));
ctorParamFns.add(bc -> bc.consume(buildItemClass));
} else if (isListOf(parameterType, MultiBuildItem.class)) {
final Class<? extends MultiBuildItem> buildItemClass = rawTypeOfParameter(parameterType, 0).asSubclass(MultiBuildItem.class);
stepConfig = stepConfig.andThen(bsb -> bsb.consumes(buildItemClass));
ctorParamFns.add(bc -> bc.consumeMulti(buildItemClass));
} else if (isConsumerOf(parameterType, BuildItem.class)) {
deprecatedProducer(parameter);
final Class<? extends BuildItem> buildItemClass = rawTypeOfParameter(parameterType, 0).asSubclass(BuildItem.class);
if (overridable) {
if (weak) {
stepConfig = stepConfig.andThen(bsb -> bsb.produces(buildItemClass, ProduceFlag.OVERRIDABLE, ProduceFlag.WEAK));
} else {
stepConfig = stepConfig.andThen(bsb -> bsb.produces(buildItemClass, ProduceFlag.OVERRIDABLE));
}
} else {
if (weak) {
stepConfig = stepConfig.andThen(bsb -> bsb.produces(buildItemClass, ProduceFlag.WEAK));
} else {
stepConfig = stepConfig.andThen(bsb -> bsb.produces(buildItemClass));
}
}
ctorParamFns.add(bc -> (Consumer<? extends BuildItem>) bc::produce);
} else if (isBuildProducerOf(parameterType, BuildItem.class)) {
deprecatedProducer(parameter);
final Class<? extends BuildItem> buildItemClass = rawTypeOfParameter(parameterType, 0).asSubclass(BuildItem.class);
if (overridable) {
if (weak) {
stepConfig = stepConfig.andThen(bsb -> bsb.produces(buildItemClass, ProduceFlag.OVERRIDABLE, ProduceFlag.WEAK));
} else {
stepConfig = stepConfig.andThen(bsb -> bsb.produces(buildItemClass, ProduceFlag.OVERRIDABLE));
}
} else {
if (weak) {
stepConfig = stepConfig.andThen(bsb -> bsb.produces(buildItemClass, ProduceFlag.WEAK));
} else {
stepConfig = stepConfig.andThen(bsb -> bsb.produces(buildItemClass));
}
}
ctorParamFns.add(bc -> (BuildProducer<? extends BuildItem>) bc::produce);
} else if (isOptionalOf(parameterType, SimpleBuildItem.class)) {
final Class<? extends SimpleBuildItem> buildItemClass = rawTypeOfParameter(parameterType, 0).asSubclass(SimpleBuildItem.class);
stepConfig = stepConfig.andThen(bsb -> bsb.consumes(buildItemClass, ConsumeFlags.of(ConsumeFlag.OPTIONAL)));
ctorParamFns.add(bc -> Optional.ofNullable(bc.consume(buildItemClass)));
} else if (isSupplierOf(parameterType, SimpleBuildItem.class)) {
final Class<? extends SimpleBuildItem> buildItemClass = rawTypeOfParameter(parameterType, 0).asSubclass(SimpleBuildItem.class);
stepConfig = stepConfig.andThen(bsb -> bsb.consumes(buildItemClass));
ctorParamFns.add(bc -> (Supplier<? extends SimpleBuildItem>) () -> bc.consume(buildItemClass));
} else if (isSupplierOfOptionalOf(parameterType, SimpleBuildItem.class)) {
final Class<? extends SimpleBuildItem> buildItemClass = rawTypeOfParameter(rawTypeOfParameter(parameterType, 0), 0).asSubclass(SimpleBuildItem.class);
stepConfig = stepConfig.andThen(bsb -> bsb.consumes(buildItemClass, ConsumeFlags.of(ConsumeFlag.OPTIONAL)));
ctorParamFns.add(bc -> (Supplier<Optional<? extends SimpleBuildItem>>) () -> Optional.ofNullable(bc.consume(buildItemClass)));
} else if (rawTypeOf(parameterType) == Executor.class) {
ctorParamFns.add(BuildContext::getExecutor);
} else if (parameterClass.isAnnotationPresent(ConfigRoot.class)) {
final ConfigRoot annotation = parameterClass.getAnnotation(ConfigRoot.class);
final ConfigPhase phase = annotation.phase();
consumingConfigPhases.add(phase);
if (phase.isAvailableAtBuild()) {
ctorParamFns.add(bc -> bc.consume(ConfigurationBuildItem.class).getReadResult().requireObjectForClass(parameterClass));
if (phase == ConfigPhase.BUILD_AND_RUN_TIME_FIXED) {
runTimeProxies.computeIfAbsent(parameterClass, readResult::requireObjectForClass);
}
} else if (phase.isReadAtMain()) {
throw reportError(parameter, phase + " configuration cannot be consumed here");
} else {
throw reportError(parameterClass, "Unknown value for ConfigPhase");
}
} else if (isRecorder(parameterClass)) {
throw reportError(parameter, "Bytecode recorders disallowed on constructor parameters");
} else {
throw reportError(parameter, "Unsupported constructor parameter type " + parameterType);
}
}
}
// index fields
final Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
final int mods = field.getModifiers();
if (Modifier.isStatic(mods)) {
// ignore static fields
continue;
}
if (Modifier.isFinal(mods)) {
// ignore final fields
continue;
}
if (!Modifier.isPublic(mods) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())) {
field.setAccessible(true);
}
// next, determine the type
final Type fieldType = field.getGenericType();
final Class<?> fieldClass = field.getType();
final boolean weak = field.isAnnotationPresent(Weak.class);
final boolean overridable = field.isAnnotationPresent(Overridable.class);
if (rawTypeExtends(fieldType, SimpleBuildItem.class)) {
final Class<? extends SimpleBuildItem> buildItemClass = rawTypeOf(fieldType).asSubclass(SimpleBuildItem.class);
stepConfig = stepConfig.andThen(bsb -> bsb.consumes(buildItemClass));
stepInstanceSetup = stepInstanceSetup.andThen((bc, o) -> ReflectUtil.setFieldVal(field, o, bc.consume(buildItemClass)));
} else if (isListOf(fieldType, MultiBuildItem.class)) {
final Class<? extends MultiBuildItem> buildItemClass = rawTypeOfParameter(fieldType, 0).asSubclass(MultiBuildItem.class);
stepConfig = stepConfig.andThen(bsb -> bsb.consumes(buildItemClass));
stepInstanceSetup = stepInstanceSetup.andThen((bc, o) -> ReflectUtil.setFieldVal(field, o, bc.consumeMulti(buildItemClass)));
} else if (isConsumerOf(fieldType, BuildItem.class)) {
deprecatedProducer(field);
final Class<? extends BuildItem> buildItemClass = rawTypeOfParameter(fieldType, 0).asSubclass(BuildItem.class);
if (overridable) {
if (weak) {
stepConfig = stepConfig.andThen(bsb -> bsb.produces(buildItemClass, ProduceFlag.OVERRIDABLE, ProduceFlag.WEAK));
} else {
stepConfig = stepConfig.andThen(bsb -> bsb.produces(buildItemClass, ProduceFlag.OVERRIDABLE));
}
} else {
if (weak) {
stepConfig = stepConfig.andThen(bsb -> bsb.produces(buildItemClass, ProduceFlag.WEAK));
} else {
stepConfig = stepConfig.andThen(bsb -> bsb.produces(buildItemClass));
}
}
stepInstanceSetup = stepInstanceSetup.andThen((bc, o) -> ReflectUtil.setFieldVal(field, o, (Consumer<? extends BuildItem>) bc::produce));
} else if (isBuildProducerOf(fieldType, BuildItem.class)) {
deprecatedProducer(field);
final Class<? extends BuildItem> buildItemClass = rawTypeOfParameter(fieldType, 0).asSubclass(BuildItem.class);
if (overridable) {
if (weak) {
stepConfig = stepConfig.andThen(bsb -> bsb.produces(buildItemClass, ProduceFlag.OVERRIDABLE, ProduceFlag.WEAK));
} else {
stepConfig = stepConfig.andThen(bsb -> bsb.produces(buildItemClass, ProduceFlag.OVERRIDABLE));
}
} else {
if (weak) {
stepConfig = stepConfig.andThen(bsb -> bsb.produces(buildItemClass, ProduceFlag.WEAK));
} else {
stepConfig = stepConfig.andThen(bsb -> bsb.produces(buildItemClass));
}
}
stepInstanceSetup = stepInstanceSetup.andThen((bc, o) -> ReflectUtil.setFieldVal(field, o, (BuildProducer<? extends BuildItem>) bc::produce));
} else if (isOptionalOf(fieldType, SimpleBuildItem.class)) {
final Class<? extends SimpleBuildItem> buildItemClass = rawTypeOfParameter(fieldType, 0).asSubclass(SimpleBuildItem.class);
stepConfig = stepConfig.andThen(bsb -> bsb.consumes(buildItemClass, ConsumeFlags.of(ConsumeFlag.OPTIONAL)));
stepInstanceSetup = stepInstanceSetup.andThen((bc, o) -> ReflectUtil.setFieldVal(field, o, Optional.ofNullable(bc.consume(buildItemClass))));
} else if (isSupplierOf(fieldType, SimpleBuildItem.class)) {
final Class<? extends SimpleBuildItem> buildItemClass = rawTypeOfParameter(fieldType, 0).asSubclass(SimpleBuildItem.class);
stepConfig = stepConfig.andThen(bsb -> bsb.consumes(buildItemClass));
stepInstanceSetup = stepInstanceSetup.andThen((bc, o) -> ReflectUtil.setFieldVal(field, o, (Supplier<? extends SimpleBuildItem>) () -> bc.consume(buildItemClass)));
} else if (isSupplierOfOptionalOf(fieldType, SimpleBuildItem.class)) {
final Class<? extends SimpleBuildItem> buildItemClass = rawTypeOfParameter(rawTypeOfParameter(fieldType, 0), 0).asSubclass(SimpleBuildItem.class);
stepConfig = stepConfig.andThen(bsb -> bsb.consumes(buildItemClass, ConsumeFlags.of(ConsumeFlag.OPTIONAL)));
stepInstanceSetup = stepInstanceSetup.andThen((bc, o) -> ReflectUtil.setFieldVal(field, o, (Supplier<Optional<? extends SimpleBuildItem>>) () -> Optional.ofNullable(bc.consume(buildItemClass))));
} else if (fieldClass == Executor.class) {
stepInstanceSetup = stepInstanceSetup.andThen((bc, o) -> ReflectUtil.setFieldVal(field, o, bc.getExecutor()));
} else if (fieldClass.isAnnotationPresent(ConfigRoot.class)) {
final ConfigRoot annotation = fieldClass.getAnnotation(ConfigRoot.class);
final ConfigPhase phase = annotation.phase();
consumingConfigPhases.add(phase);
if (phase.isAvailableAtBuild()) {
stepInstanceSetup = stepInstanceSetup.andThen((bc, o) -> {
final ConfigurationBuildItem configurationBuildItem = bc.consume(ConfigurationBuildItem.class);
ReflectUtil.setFieldVal(field, o, configurationBuildItem.getReadResult().requireObjectForClass(fieldClass));
});
if (phase == ConfigPhase.BUILD_AND_RUN_TIME_FIXED) {
runTimeProxies.computeIfAbsent(fieldClass, readResult::requireObjectForClass);
}
} else if (phase.isReadAtMain()) {
throw reportError(field, phase + " configuration cannot be consumed here");
} else {
throw reportError(fieldClass, "Unknown value for ConfigPhase");
}
} else if (isRecorder(fieldClass)) {
throw reportError(field, "Bytecode recorders disallowed on fields");
} else {
throw reportError(field, "Unsupported field type " + fieldType);
}
}
// now iterate the methods
final List<Method> methods = getMethods(clazz);
for (Method method : methods) {
final BuildStep buildStep = method.getAnnotation(BuildStep.class);
if (buildStep == null) {
continue;
}
if (Modifier.isStatic(method.getModifiers())) {
throw new RuntimeException("A build step must be a non-static method: " + method);
}
if (!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) {
method.setAccessible(true);
}
final Class<? extends BooleanSupplier>[] onlyIf = buildStep.onlyIf();
final Class<? extends BooleanSupplier>[] onlyIfNot = buildStep.onlyIfNot();
final Parameter[] methodParameters = method.getParameters();
final Record recordAnnotation = method.getAnnotation(Record.class);
final boolean isRecorder = recordAnnotation != null;
final boolean identityComparison = isRecorder ? recordAnnotation.useIdentityComparisonForParameters() : true;
if (isRecorder) {
boolean recorderFound = false;
for (Class<?> p : method.getParameterTypes()) {
if (isRecorder(p)) {
recorderFound = true;
break;
}
}
if (!recorderFound) {
throw new RuntimeException(method + " is marked @Record but does not inject an @Recorder object");
}
}
final List<BiFunction<BuildContext, BytecodeRecorderImpl, Object>> methodParamFns;
Consumer<BuildStepBuilder> methodStepConfig = Functions.discardingConsumer();
BooleanSupplier addStep = () -> true;
for (boolean inv : new boolean[] { false, true }) {
Class<? extends BooleanSupplier>[] testClasses = inv ? onlyIfNot : onlyIf;
for (Class<? extends BooleanSupplier> testClass : testClasses) {
BooleanSupplier bs = supplierFactory.get((Class<? extends BooleanSupplier>) testClass);
if (inv) {
addStep = and(addStep, not(bs));
} else {
addStep = and(addStep, bs);
}
}
}
final BooleanSupplier finalAddStep = addStep;
if (isRecorder) {
assert recordAnnotation != null;
final ExecutionTime executionTime = recordAnnotation.value();
final boolean optional = recordAnnotation.optional();
methodStepConfig = methodStepConfig.andThen(bsb -> {
bsb.produces(executionTime == ExecutionTime.STATIC_INIT ? StaticBytecodeRecorderBuildItem.class : MainBytecodeRecorderBuildItem.class, optional ? ProduceFlags.of(ProduceFlag.WEAK) : ProduceFlags.NONE);
});
}
EnumSet<ConfigPhase> methodConsumingConfigPhases = consumingConfigPhases.clone();
if (methodParameters.length == 0) {
methodParamFns = Collections.emptyList();
} else {
methodParamFns = new ArrayList<>(methodParameters.length);
for (Parameter parameter : methodParameters) {
final boolean weak = parameter.isAnnotationPresent(Weak.class);
final boolean overridable = parameter.isAnnotationPresent(Overridable.class);
final Type parameterType = parameter.getParameterizedType();
final Class<?> parameterClass = parameter.getType();
if (rawTypeExtends(parameterType, SimpleBuildItem.class)) {
final Class<? extends SimpleBuildItem> buildItemClass = parameterClass.asSubclass(SimpleBuildItem.class);
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.consumes(buildItemClass));
methodParamFns.add((bc, bri) -> bc.consume(buildItemClass));
} else if (isListOf(parameterType, MultiBuildItem.class)) {
final Class<? extends MultiBuildItem> buildItemClass = rawTypeOfParameter(parameterType, 0).asSubclass(MultiBuildItem.class);
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.consumes(buildItemClass));
methodParamFns.add((bc, bri) -> bc.consumeMulti(buildItemClass));
} else if (isConsumerOf(parameterType, BuildItem.class)) {
final Class<? extends BuildItem> buildItemClass = rawTypeOfParameter(parameterType, 0).asSubclass(BuildItem.class);
if (overridable) {
if (weak) {
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.produces(buildItemClass, ProduceFlag.OVERRIDABLE, ProduceFlag.WEAK));
} else {
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.produces(buildItemClass, ProduceFlag.OVERRIDABLE));
}
} else {
if (weak) {
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.produces(buildItemClass, ProduceFlag.WEAK));
} else {
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.produces(buildItemClass));
}
}
methodParamFns.add((bc, bri) -> (Consumer<? extends BuildItem>) bc::produce);
} else if (isBuildProducerOf(parameterType, BuildItem.class)) {
final Class<? extends BuildItem> buildItemClass = rawTypeOfParameter(parameterType, 0).asSubclass(BuildItem.class);
if (overridable) {
if (weak) {
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.produces(buildItemClass, ProduceFlag.OVERRIDABLE, ProduceFlag.WEAK));
} else {
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.produces(buildItemClass, ProduceFlag.OVERRIDABLE));
}
} else {
if (weak) {
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.produces(buildItemClass, ProduceFlag.WEAK));
} else {
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.produces(buildItemClass));
}
}
methodParamFns.add((bc, bri) -> (BuildProducer<? extends BuildItem>) bc::produce);
} else if (isOptionalOf(parameterType, SimpleBuildItem.class)) {
final Class<? extends SimpleBuildItem> buildItemClass = rawTypeOfParameter(parameterType, 0).asSubclass(SimpleBuildItem.class);
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.consumes(buildItemClass, ConsumeFlags.of(ConsumeFlag.OPTIONAL)));
methodParamFns.add((bc, bri) -> Optional.ofNullable(bc.consume(buildItemClass)));
} else if (isSupplierOf(parameterType, SimpleBuildItem.class)) {
final Class<? extends SimpleBuildItem> buildItemClass = rawTypeOfParameter(parameterType, 0).asSubclass(SimpleBuildItem.class);
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.consumes(buildItemClass));
methodParamFns.add((bc, bri) -> (Supplier<? extends SimpleBuildItem>) () -> bc.consume(buildItemClass));
} else if (isSupplierOfOptionalOf(parameterType, SimpleBuildItem.class)) {
final Class<? extends SimpleBuildItem> buildItemClass = rawTypeOfParameter(rawTypeOfParameter(parameterType, 0), 0).asSubclass(SimpleBuildItem.class);
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.consumes(buildItemClass, ConsumeFlags.of(ConsumeFlag.OPTIONAL)));
methodParamFns.add((bc, bri) -> (Supplier<Optional<? extends SimpleBuildItem>>) () -> Optional.ofNullable(bc.consume(buildItemClass)));
} else if (rawTypeOf(parameterType) == Executor.class) {
methodParamFns.add((bc, bri) -> bc.getExecutor());
} else if (parameterClass.isAnnotationPresent(ConfigRoot.class)) {
final ConfigRoot annotation = parameterClass.getAnnotation(ConfigRoot.class);
final ConfigPhase phase = annotation.phase();
methodConsumingConfigPhases.add(phase);
if (phase.isAvailableAtBuild()) {
methodParamFns.add((bc, bri) -> {
final ConfigurationBuildItem configurationBuildItem = bc.consume(ConfigurationBuildItem.class);
return configurationBuildItem.getReadResult().requireObjectForClass(parameterClass);
});
if (isRecorder && phase == ConfigPhase.BUILD_AND_RUN_TIME_FIXED) {
runTimeProxies.computeIfAbsent(parameterClass, readResult::requireObjectForClass);
}
} else if (phase.isReadAtMain()) {
if (isRecorder) {
methodParamFns.add((bc, bri) -> {
final RunTimeConfigurationProxyBuildItem proxies = bc.consume(RunTimeConfigurationProxyBuildItem.class);
return proxies.getProxyObjectFor(parameterClass);
});
runTimeProxies.computeIfAbsent(parameterClass, ConfigMappingUtils::newInstance);
} else {
throw reportError(parameter, phase + " configuration cannot be consumed here unless the method is a @Recorder");
}
} else {
throw reportError(parameterClass, "Unknown value for ConfigPhase");
}
} else if (isRecorder(parameter.getType())) {
if (!isRecorder) {
throw reportError(parameter, "Cannot pass recorders to method which is not annotated with " + Record.class);
}
methodParamFns.add((bc, bri) -> {
assert bri != null;
return bri.getRecordingProxy(parameterClass);
});
// now look for recorder parameter injection
// as we now inject config directly into recorders we need to look at the constructor params
Constructor<?>[] ctors = parameter.getType().getDeclaredConstructors();
for (var ctor : ctors) {
if (ctors.length == 1 || ctor.isAnnotationPresent(Inject.class)) {
for (var type : ctor.getGenericParameterTypes()) {
Class<?> theType = null;
if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) type;
if (pt.getRawType().equals(RuntimeValue.class)) {
theType = (Class<?>) pt.getActualTypeArguments()[0];
} else {
throw new RuntimeException("Unknown recorder constructor parameter: " + type + " in recorder " + parameter.getType());
}
} else {
theType = (Class<?>) type;
}
ConfigRoot annotation = theType.getAnnotation(ConfigRoot.class);
if (annotation != null) {
if (recordAnnotation.value() == ExecutionTime.STATIC_INIT) {
methodConsumingConfigPhases.add(ConfigPhase.BUILD_AND_RUN_TIME_FIXED);
} else {
methodConsumingConfigPhases.add(annotation.phase());
}
if (annotation.phase().isReadAtMain()) {
runTimeProxies.computeIfAbsent(theType, ConfigMappingUtils::newInstance);
} else {
runTimeProxies.computeIfAbsent(theType, readResult::requireObjectForClass);
}
}
}
}
}
} else if (parameter.getType() == RecorderContext.class || parameter.getType() == BytecodeRecorderImpl.class) {
if (!isRecorder) {
throw reportError(parameter, "Cannot pass recorder context to method which is not annotated with " + Record.class);
}
methodParamFns.add((bc, bri) -> bri);
} else {
throw reportError(parameter, "Unsupported method parameter " + parameterType);
}
}
}
final BiConsumer<BuildContext, Object> resultConsumer;
final Type returnType = method.getGenericReturnType();
final boolean weak = method.isAnnotationPresent(Weak.class);
final boolean overridable = method.isAnnotationPresent(Overridable.class);
if (rawTypeIs(returnType, void.class)) {
resultConsumer = Functions.discardingBiConsumer();
} else if (rawTypeExtends(returnType, BuildItem.class)) {
final Class<? extends BuildItem> type = method.getReturnType().asSubclass(BuildItem.class);
if (overridable) {
if (weak) {
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.produces(type, ProduceFlag.OVERRIDABLE, ProduceFlag.WEAK));
} else {
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.produces(type, ProduceFlag.OVERRIDABLE));
}
} else {
if (weak) {
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.produces(type, ProduceFlag.WEAK));
} else {
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.produces(type));
}
}
resultConsumer = (bc, o) -> {
if (o != null)
bc.produce((BuildItem) o);
};
} else if (isOptionalOf(returnType, BuildItem.class)) {
final Class<? extends BuildItem> type = rawTypeOfParameter(returnType, 0).asSubclass(BuildItem.class);
if (overridable) {
if (weak) {
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.produces(type, ProduceFlag.OVERRIDABLE, ProduceFlag.WEAK));
} else {
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.produces(type, ProduceFlag.OVERRIDABLE));
}
} else {
if (weak) {
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.produces(type, ProduceFlag.WEAK));
} else {
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.produces(type));
}
}
resultConsumer = (bc, o) -> ((Optional<? extends BuildItem>) o).ifPresent(bc::produce);
} else if (isListOf(returnType, MultiBuildItem.class)) {
final Class<? extends MultiBuildItem> type = rawTypeOfParameter(returnType, 0).asSubclass(MultiBuildItem.class);
if (overridable) {
if (weak) {
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.produces(type, ProduceFlag.OVERRIDABLE, ProduceFlag.WEAK));
} else {
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.produces(type, ProduceFlag.OVERRIDABLE));
}
} else {
if (weak) {
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.produces(type, ProduceFlag.WEAK));
} else {
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.produces(type));
}
}
resultConsumer = (bc, o) -> {
if (o != null)
bc.produce((List<? extends MultiBuildItem>) o);
};
} else {
throw reportError(method, "Unsupported method return type " + returnType);
}
if (methodConsumingConfigPhases.contains(ConfigPhase.BOOTSTRAP) || methodConsumingConfigPhases.contains(ConfigPhase.RUN_TIME)) {
if (isRecorder && recordAnnotation.value() == ExecutionTime.STATIC_INIT) {
throw reportError(method, "Bytecode recorder is static but an injected config object is declared as run time");
}
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.consumes(RunTimeConfigurationProxyBuildItem.class));
if (methodConsumingConfigPhases.contains(ConfigPhase.BOOTSTRAP)) {
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.afterProduce(BootstrapConfigSetupCompleteBuildItem.class));
}
if (methodConsumingConfigPhases.contains(ConfigPhase.RUN_TIME)) {
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.afterProduce(RuntimeConfigSetupCompleteBuildItem.class));
}
}
if (methodConsumingConfigPhases.contains(ConfigPhase.BUILD_AND_RUN_TIME_FIXED) || methodConsumingConfigPhases.contains(ConfigPhase.BUILD_TIME)) {
methodStepConfig = methodStepConfig.andThen(bsb -> bsb.consumes(ConfigurationBuildItem.class));
}
final Consume[] consumes = method.getAnnotationsByType(Consume.class);
if (consumes.length > 0) {
methodStepConfig = methodStepConfig.andThen(bsb -> {
for (Consume consume : consumes) {
bsb.afterProduce(consume.value());
}
});
}
final Produce[] produces = method.getAnnotationsByType(Produce.class);
if (produces.length > 0) {
methodStepConfig = methodStepConfig.andThen(bsb -> {
for (Produce produce : produces) {
bsb.beforeConsume(produce.value());
}
});
}
final ProduceWeak[] produceWeaks = method.getAnnotationsByType(ProduceWeak.class);
if (produceWeaks.length > 0) {
methodStepConfig = methodStepConfig.andThen(bsb -> {
for (ProduceWeak produceWeak : produceWeaks) {
bsb.beforeConsume(produceWeak.value(), ProduceFlag.WEAK);
}
});
}
final Consumer<BuildStepBuilder> finalStepConfig = stepConfig.andThen(methodStepConfig).andThen(buildStepBuilder -> buildStepBuilder.buildIf(finalAddStep));
final BiConsumer<BuildContext, Object> finalStepInstanceSetup = stepInstanceSetup;
final String name = clazz.getName() + "#" + method.getName();
chainConfig = chainConfig.andThen(bcb -> {
BuildStepBuilder bsb = bcb.addBuildStep(new io.quarkus.builder.BuildStep() {
public void execute(final BuildContext bc) {
Object[] ctorArgs = new Object[ctorParamFns.size()];
for (int i = 0; i < ctorArgs.length; i++) {
ctorArgs[i] = ctorParamFns.get(i).apply(bc);
}
Object instance;
try {
instance = constructor.newInstance(ctorArgs);
} catch (InstantiationException e) {
throw ReflectUtil.toError(e);
} catch (IllegalAccessException e) {
throw ReflectUtil.toError(e);
} catch (InvocationTargetException e) {
try {
throw e.getCause();
} catch (RuntimeException | Error e2) {
throw e2;
} catch (Throwable t) {
throw new IllegalStateException(t);
}
}
finalStepInstanceSetup.accept(bc, instance);
Object[] methodArgs = new Object[methodParamFns.size()];
BytecodeRecorderImpl bri = isRecorder ? new BytecodeRecorderImpl(recordAnnotation.value() == ExecutionTime.STATIC_INIT, clazz.getSimpleName(), method.getName(), Integer.toString(Math.abs(method.toString().hashCode())), identityComparison, s -> {
if (s instanceof Class) {
var cfg = ((Class<?>) s).getAnnotation(ConfigRoot.class);
if (cfg == null || (cfg.phase() != ConfigPhase.BUILD_AND_RUN_TIME_FIXED && recordAnnotation.value() == ExecutionTime.STATIC_INIT)) {
throw new RuntimeException("Can only inject BUILD_AND_RUN_TIME_FIXED objects into a constructor, use RuntimeValue to inject runtime config: " + s);
}
return runTimeProxies.get(s);
}
if (s instanceof ParameterizedType) {
ParameterizedType p = (ParameterizedType) s;
if (p.getRawType() == RuntimeValue.class) {
Object object = runTimeProxies.get(p.getActualTypeArguments()[0]);
if (object == null) {
return new RuntimeValue<>();
}
return new RuntimeValue<>(object);
}
}
return null;
}) : null;
for (int i = 0; i < methodArgs.length; i++) {
methodArgs[i] = methodParamFns.get(i).apply(bc, bri);
}
Object result;
try {
result = method.invoke(instance, methodArgs);
} catch (IllegalAccessException e) {
throw ReflectUtil.toError(e);
} catch (InvocationTargetException e) {
try {
throw e.getCause();
} catch (RuntimeException | Error e2) {
throw e2;
} catch (Throwable t) {
throw new IllegalStateException(t);
}
}
resultConsumer.accept(bc, result);
if (isRecorder) {
// commit recorded data
if (recordAnnotation.value() == ExecutionTime.STATIC_INIT) {
bc.produce(new StaticBytecodeRecorderBuildItem(bri));
} else {
bc.produce(new MainBytecodeRecorderBuildItem(bri));
}
}
}
public String toString() {
return name;
}
});
finalStepConfig.accept(bsb);
});
}
return chainConfig;
}
Aggregations