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

[Main] SR Config 3.11 causes exception on startup #45549

Closed
manofthepeace opened this issue Jan 13, 2025 · 9 comments
Closed

[Main] SR Config 3.11 causes exception on startup #45549

manofthepeace opened this issue Jan 13, 2025 · 9 comments
Labels
area/config kind/bug Something isn't working

Comments

@manofthepeace
Copy link
Contributor

manofthepeace commented Jan 13, 2025

Describe the bug

Was a bit worried about this update due to smallrye/smallrye-config#1264 . With it my app did break, but not where I actually expected it to break.

Where it break;

public class Feature1HttpConfigValidator implements ConstraintValidator<ValidFeature1HttpConfig, Feature1HttpConfig> {
    @Override
    public boolean isValid(Feature1HttpConfig feature1Config, ConstraintValidatorContext context) {
            ChannelConfig config = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class)
              .getConfigMapping(AnotherConfig.class);
    }
}

causes; java.util.NoSuchElementException: SRCFG00027: Could not find a mapping for org.acme.config.AnotherConfig

Expected behavior

config should be there and work.

Actual behavior

exception is thrown

How to Reproduce?

reproducer

1- Application will start as is. (quarkus:dev)
2- Change quarkus version to 999-SNAPSHOT (one that includes sr config 3.11)
3- application will not start (quarkus:dev)

Output of uname -a or ver

Darwin Kernel Version 24.2.0

Output of java -version

openjdk version "21.0.5" 2024-10-15 LTS

Quarkus version or git rev

main

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

mvn 3.9.9

Additional information

No response

@manofthepeace manofthepeace added the kind/bug Something isn't working label Jan 13, 2025
Copy link

quarkus-bot bot commented Jan 13, 2025

/cc @radcortez (config)

@manofthepeace manofthepeace changed the title [Main]. SR Config 3.11 breaks my app [Main] SR Config 3.11 causes exception on startup Jan 14, 2025
@manofthepeace
Copy link
Contributor Author

I have added a reproducer in the OP

@gsmet
Copy link
Member

gsmet commented Jan 14, 2025

TBH, I'm not entirely sure this is a supported use case but I will let @radcortez comment on this.

@manofthepeace
Copy link
Contributor Author

Right, all I can say is that it worked since pretty much forever in my case. If it's not supported I'd appreciate a workaround when the validation needs to depend on the configvalue of another unrelated ConfigMapping (which cannot logically be part of the other)

@radcortez
Copy link
Member

The Config validation was executed only at mapping retrieval because we had a circular dependency between Config and the Validator. We required the Config to create the Validator and late bind it, so we went with that approach, but that was not the original plan. The plan was to perform the validation when the mapping was populated. For instance, populating a mapping can generate a few errors (required, expression expansion, etc.). It didn't make much sense for the Validator validations to be executed at a different time (which could happen long after the runtime started).

When we added a standalone Config for the Validator in #32586, that limitation went away, but we never fixed the original behaviour, until now.

I would say that if there is a dependency in the validation, then the configuration should probably be part of the same tree, and that would work. The only option I see at the moment is to retrieve any configuration by its name (instead of the mapping).

I can try to think of some other options, but in reality, we never thought about this use case, and it only worked because of our own limitations :)

@manofthepeace
Copy link
Contributor Author

It didn't make much sense for the Validator validations to be executed at a different time (which could happen long after the runtime started).

totally makes sense.

When we added a standalone Config for the Validator in #32586, that limitation went away, but we never fixed the original behaviour, until now.

interesting that fixes a bug from an older me.

The only option I see at the moment is to retrieve any configuration by its name (instead of the mapping).

ok yes that's what I thought.

I have a problem with the above though. my config mapping is like this;

@StaticInitSafe
@ConfigMapping(prefix = "conf")
public interface Config {

    @WithName("value")
    List<InnterMapping> value();

    interface InnerMapping {
        String key();

        List<String> id();
    }
}

when I do; List<InnerMapping> values = config.getValues("conf.value", InnerMapping.class);

I get
java.lang.IllegalArgumentException: SRCFG00013: No Converter registered for interface org.acme.Config$InnterMapping

can I make the getValues not try to run a converter, but use the sub interface of the mapping?

@manofthepeace
Copy link
Contributor Author

Simplest I found is something like this;

        SmallRyeConfig config = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class);
        Function<String, List<List<String>>> fetchValues = source -> {
            List<Integer> indices = config.getIndexedPropertiesIndexes(source);
            return indices.stream()
                    .map(i -> config.getValues(source + "[" + i + "].id", String.class))
                    .collect(Collectors.toList());
        };

@radcortez
Copy link
Member

Here is another trick that you can use:

SmallRyeConfig config = ConfigProvider.getConfig().unwrap(SmallRyeConfig.class);
// There may be cases where a Config with the mappings is already available, but we can't be sure, so we wrap
// the original Config and map the logging classes.
SmallRyeConfig loggingConfig = new SmallRyeConfigBuilder()
.withCustomizers(new QuarkusConfigBuilderCustomizer())
.withMapping(LogBuildTimeConfig.class)
.withMapping(LogRuntimeConfig.class)
.withMapping(ConsoleRuntimeConfig.class)
.withSources(new ConfigSource() {
@Override
public Set<String> getPropertyNames() {
Set<String> properties = new HashSet<>();
config.getPropertyNames().forEach(properties::add);
return properties;
}
@Override
public String getValue(final String propertyName) {
return config.getRawValue(propertyName);
}
@Override
public String getName() {
return "Logging Config";
}
}).build();
LogRuntimeConfig logRuntimeConfig = loggingConfig.getConfigMapping(LogRuntimeConfig.class);
LogBuildTimeConfig logBuildTimeConfig = loggingConfig.getConfigMapping(LogBuildTimeConfig.class);
ConsoleRuntimeConfig consoleRuntimeConfig = loggingConfig.getConfigMapping(ConsoleRuntimeConfig.class);

You just create a new instance of SmallRyeConfig, with a custom ConfigSource that delegates the relevant lookups to the current config.

@manofthepeace
Copy link
Contributor Author

That's a neat trick. Thanks. So I think this is overall as designed, so let's close this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/config kind/bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants