Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't @Inject a @ConfigMapping Interface on a Validator #23879

Closed
nunocasteleira opened this issue Feb 22, 2022 · 8 comments · Fixed by #24450
Closed

Can't @Inject a @ConfigMapping Interface on a Validator #23879

nunocasteleira opened this issue Feb 22, 2022 · 8 comments · Fixed by #24450
Labels
area/config area/hibernate-validator Hibernate Validator kind/bug Something isn't working triage/needs-reproducer We are waiting for a reproducer.
Milestone

Comments

@nunocasteleira
Copy link

Describe the bug

I implemented a @ConfigMapping Interface to pass configurations via application.yaml file, annotated it with @StaticInitSafe but I can't build my app when I @Inject it on a @ApplicationScoped ConstraintValidator.

I already was using Configurations with the @ConfigProperty(name = "configname") annotation and it works, but I implemented configurations via the interface as I'm understanding that it was deprecated and I needed to mock it.

Am I doing something wrong or is it a bug?

Expected behavior

No response

Actual behavior

No response

How to Reproduce?

No response

Output of uname -a or ver

No response

Output of java -version

Oracle JDK 11

GraalVM version (if different from Java)

No response

Quarkus version or git rev

2.7.0.Final

Build tool (ie. output of mvnw --version or gradlew --version)

Apache Maven 3.8.4 (9b656c72d54e5bacbed989b64718c159fe39b537)

Additional information

No response

@nunocasteleira nunocasteleira added the kind/bug Something isn't working label Feb 22, 2022
@gsmet
Copy link
Member

gsmet commented Feb 22, 2022

Please provide a reproducer (and also add the error you obtain in the description).

@gsmet gsmet added triage/needs-reproducer We are waiting for a reproducer. area/config area/hibernate-validator Hibernate Validator and removed triage/needs-triage labels Feb 22, 2022
@nunocasteleira
Copy link
Author

Sorry, should have done that immediately.

Config class:

@StaticInitSafe
@ConfigMapping(prefix = "app")
public interface AppConfig {

    @WithName("feature-property")
    FeatureProperty featureProperty();

    interface FeatureProperty {
        @WithDefault("0.5")
        double configPercentage();
    }
}

Validator class:

@ApplicationScoped
public class CreateEntityValidator implements ConstraintValidator<CreateEntityValidator , EntityRequest> {
// This way it works
//    @ConfigProperty(name = "app.feature-property.config-percentage")
//    double configPercentage;

    @Inject
    protected AppConfig appConfig;

    public boolean isValid(final EntityRequest entityRequest,
            final ConstraintValidatorContext constraintValidatorContext) {
        this.isValid = true;
        this.errorMessage = new StringBuilder();
        constraintValidatorContext.disableDefaultConstraintViolation();

        if (teamSpaceMaxCapacity < Math.ceil((double) placeCapacity * appConfig.featureProperty().configPercentage())) {
                this.isValid = false;
            }

        return isValid;
    }
}

Error:

2022-02-23 10:09:42,612 ERROR [io.qua.run.boo.StartupActionImpl] (Quarkus Main Thread) Error running Quarkus: java.lang.reflect.InvocationTargetException
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at io.quarkus.runner.bootstrap.StartupActionImpl$1.run(StartupActionImpl.java:103)
	at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.ExceptionInInitializerError
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
	at java.base/java.lang.Class.newInstance(Class.java:584)
	at io.quarkus.runtime.Quarkus.run(Quarkus.java:66)
	at io.quarkus.runtime.Quarkus.run(Quarkus.java:41)
	at io.quarkus.runtime.Quarkus.run(Quarkus.java:120)
	at io.quarkus.runner.GeneratedMain.main(Unknown Source)
	... 6 more
Caused by: java.lang.RuntimeException: Failed to start quarkus
	at io.quarkus.runner.ApplicationImpl.<clinit>(Unknown Source)
	... 15 more
Caused by: javax.validation.ValidationException: HV000032: Unable to initialize net.domain.validation.CreateBookingValidator_ClientProxy.

@radcortez
Copy link
Member

@nunocasteleira thank you. Unfortunately, this is not enough. If I copy-paste your code, there are still missing things and I'm unable to get a running reproducer. I could fill in the blanks, but it could deviate from your original issue. Are you able to provide a small GH repo, with a working example? Thank you.

@nunocasteleira
Copy link
Author

@radcortez I'm not able to reproduce this error on a clean project, so clearly I'm doing something wrong. In theory this is what I want to do and on this repo it is working: https://github.com/nunocasteleira/quarkus-error-on-validation

@radcortez
Copy link
Member

I had a quick look and the reproducer is missing the dependency for the runtime Hibernate Validator (the Validator API is available because of RESTEasy, but they are not being read).

I don't get the same stacktrace as you, but I noticed an issue where we have a circular dependency between the config mapping and the Validator. The issue is that because the Validator is available, we will try to validate the mapping, but the Validator tries to create the ConstraintValidator implementations, which injects a mapping class. I'm not sure if we can do something about this. Maybe something that allows you to skip the Validator on the mapping side.

For now, a way to fix it is to just inject an Instance<SmallRyeConfig> config; and retrieve the mapping programmatically with config().getConfigMapping(AppConfig.class).

Instance<AppConfig> appConfig; should also work, but I'm having an error, so it may be a separate thing. I'll have a look.

@radcortez
Copy link
Member

Also, because you are retrieving the mapping programmatically, you need to annotate it with @Unremovable so Quarkus registers it (Quarkus drops things that it thinks are not being used). You can also drop the @StaticInitSafe annotation.

@nunocasteleira
Copy link
Author

Thanks for the replies. Just to be sure, Is this approach better than using @ConfigMapping, right? Is there a problem with retrieving it programmatically?

@radcortez
Copy link
Member

You still conserve the mapping, you just retrieve it programmatically lazyly to break up the circular dependency.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/config area/hibernate-validator Hibernate Validator kind/bug Something isn't working triage/needs-reproducer We are waiting for a reproducer.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants