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

#1001 Application-level profile and property management #1109

Merged
merged 22 commits into from
Dec 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
160790b
#1001 Set up basic property management and parsing API
GuusLieben Jul 17, 2024
4c57ca4
#1001 Initialize property registry during application initialization
GuusLieben Jul 17, 2024
d3668db
#1001 Allow creating and parsing complex property views
GuusLieben Jul 17, 2024
4faa76f
#1001 Set up profile registry API for profile-specific properties
GuusLieben Jul 17, 2024
28c9f23
#1001 Add stream utilities for working with Map.Entry
GuusLieben Jul 17, 2024
aec4c02
#1001 Implement object- and list based property access
GuusLieben Dec 21, 2024
1ee8609
#1001 Update ClassPathResourceLookupStrategy to use environment directly
GuusLieben Dec 21, 2024
20db0a4
#1001 Add documentation to property configuration components
GuusLieben Dec 22, 2024
de8fca2
#1001 Fix incorrect contains check in MapProperty list lookup
GuusLieben Dec 22, 2024
b5e1d81
#1001 Bump Logback due to OWASP CVE block
GuusLieben Dec 22, 2024
37a535a
#1001 Add property accessing tests, fix accessor matching
GuusLieben Dec 22, 2024
757fb7e
#1001 Simplify bulk-registering of properties in property registries
GuusLieben Dec 23, 2024
4c4c88d
#1001 Expand documentation for `@PropertiesSource`
GuusLieben Dec 23, 2024
8215215
#1001 Fix incorrect collectors for annotation introspectors
GuusLieben Dec 23, 2024
65d95c7
#1001 Add integration test for property bootstrapping in Launchpad ap…
GuusLieben Dec 23, 2024
8412228
#1001 Allow injecting property values into injection points
GuusLieben Dec 23, 2024
9d12254
#1001 Support annotation hierarchies in test parameter resolvers
GuusLieben Dec 23, 2024
2962126
#1001 Allow customising conversion service and converter registry bef…
GuusLieben Dec 23, 2024
59b28c5
#1001 Add documentation for property value injection components
GuusLieben Dec 23, 2024
b1883ba
#1001 Rename loaders to clarify path-based resource loading
GuusLieben Dec 23, 2024
c66fe47
#1001 Fix minor documentation issues
GuusLieben Dec 24, 2024
14b5be7
#1001 Remove unused property holder (replaced by PropertyRegistry)
GuusLieben Dec 24, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions hartshorn-assembly/pom.assembly.xml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,14 @@
<groupId>org.dockbox.hartshorn</groupId>
<artifactId>hartshorn-reporting</artifactId>
</dependency>
<dependency>
<groupId>org.dockbox.hartshorn</groupId>
<artifactId>hartshorn-profiles</artifactId>
</dependency>
<dependency>
<groupId>org.dockbox.hartshorn</groupId>
<artifactId>hartshorn-properties</artifactId>
</dependency>
<dependency>
<groupId>org.dockbox.hartshorn</groupId>
<artifactId>hartshorn-util</artifactId>
Expand Down
12 changes: 11 additions & 1 deletion hartshorn-bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
<javax.inject.version>1</javax.inject.version>
<javax.annotations.version>1.3.2</javax.annotations.version>
<junit.version>5.10.3</junit.version>
<logback.version>1.5.6</logback.version>
<logback.version>1.5.15</logback.version>
<mockito.version>5.12.0</mockito.version>
<slf4j.version>2.0.13</slf4j.version>
</properties>
Expand All @@ -47,6 +47,16 @@
<artifactId>hartshorn-util</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.dockbox.hartshorn</groupId>
<artifactId>hartshorn-properties</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.dockbox.hartshorn</groupId>
<artifactId>hartshorn-profiles</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.dockbox.hartshorn</groupId>
<artifactId>hartshorn-spi</artifactId>
Expand Down
4 changes: 4 additions & 0 deletions hartshorn-inject-configurations/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
<groupId>org.dockbox.hartshorn</groupId>
<artifactId>hartshorn-inject</artifactId>
</dependency>
<dependency>
<groupId>org.dockbox.hartshorn</groupId>
<artifactId>hartshorn-properties</artifactId>
</dependency>

<dependency>
<groupId>org.dockbox.hartshorn</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.dockbox.hartshorn.inject.condition.Condition;
import org.dockbox.hartshorn.inject.condition.ConditionContext;
import org.dockbox.hartshorn.inject.condition.ConditionResult;
import org.dockbox.hartshorn.properties.ValueProperty;
import org.dockbox.hartshorn.util.option.Option;

/**
Expand All @@ -39,23 +40,35 @@ public class PropertyCondition implements Condition {
public ConditionResult matches(ConditionContext context) {
return context.annotatedElement().annotations().get(RequiresProperty.class).map(condition -> {
String name = condition.name();
Option<String> result = context.application().properties().property(name);
Option<ValueProperty> result = context.application()
.environment()
.propertyRegistry()
.get(name);
if (result.absent()) {
if (condition.matchIfMissing()) {
return ConditionResult.matched();
}
return ConditionResult.notFound("property", name);
}

String value = result.get();
if (condition.matchIfMissing()) {
return ConditionResult.found("property", name, value);
ValueProperty property = result.get();
Option<String> value = property.value();
if (condition.matchIfMissing() && value.present()) {
return ConditionResult.found("property", name, value.get());
}

if (condition.withValue().isEmpty()) {
return ConditionResult.matched();
}
return condition.withValue().equals(value) ? ConditionResult.matched() : ConditionResult.notEqual("property", condition.withValue(), value);
else if (value.absent()) {
return ConditionResult.notFound("property", name);
}
else {
String actualValue = value.get();
return condition.withValue().equals(actualValue)
? ConditionResult.matched()
: ConditionResult.notEqual("property", condition.withValue(), actualValue);
}
}).orCompute(() -> ConditionResult.invalidCondition("property")).get();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,20 @@

package org.dockbox.hartshorn.inject.condition.support;

import org.dockbox.hartshorn.inject.condition.RequiresCondition;
import org.dockbox.hartshorn.properties.PropertyRegistry;
import org.dockbox.hartshorn.util.introspect.annotations.AttributeAlias;
import org.dockbox.hartshorn.util.introspect.annotations.Extends;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.dockbox.hartshorn.inject.ApplicationPropertyHolder;
import org.dockbox.hartshorn.inject.condition.RequiresCondition;
import org.dockbox.hartshorn.util.introspect.annotations.AttributeAlias;
import org.dockbox.hartshorn.util.introspect.annotations.Extends;

/**
* A condition that requires a property to be present in the application's {@link ApplicationPropertyHolder}.
* The property is resolved by name, and optionally by value. If the value is not specified, the property is
* required to be present and have any value.
* A condition that requires a property to be present in the application's {@link PropertyRegistry}. The property
* is resolved by name, and optionally by value. If the value is not specified, the property is required to be
* present and have any value.
*
* @see PropertyCondition
*
Expand Down
4 changes: 4 additions & 0 deletions hartshorn-inject/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
<groupId>org.dockbox.hartshorn</groupId>
<artifactId>hartshorn-spi</artifactId>
</dependency>
<dependency>
<groupId>org.dockbox.hartshorn</groupId>
<artifactId>hartshorn-properties</artifactId>
</dependency>

<dependency>
<groupId>org.dockbox.hartshorn</groupId>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,4 @@ public interface InjectionCapableApplication extends Context {
ComponentProvider defaultProvider();

HierarchicalBinder defaultBinder();

ApplicationPropertyHolder properties();
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import org.dockbox.hartshorn.inject.targets.ComponentInjectionPoint;
import org.dockbox.hartshorn.inject.targets.ComponentInjectionPointsResolver;
import org.dockbox.hartshorn.properties.PropertyRegistry;
import org.dockbox.hartshorn.proxy.ProxyOrchestrator;
import org.dockbox.hartshorn.util.introspect.Introspector;

Expand Down Expand Up @@ -69,5 +70,7 @@ public interface InjectorEnvironment {

InjectorConfiguration configuration();

PropertyRegistry propertyRegistry();

ExceptionHandler exceptionHandler();
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import org.dockbox.hartshorn.inject.annotations.Named;
import org.dockbox.hartshorn.util.TypeUtils;
import org.dockbox.hartshorn.util.stream.EntryStream;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
Expand Down Expand Up @@ -139,8 +140,8 @@ public int hashCode() {

@Override
public String toString() {
String metaString = this.meta.entrySet().stream()
.map(entry -> "%s=%s".formatted(entry.getKey(), entry.getValue()))
String metaString = EntryStream.of(this.meta)
.map((key, value) -> "%s=%s".formatted(key, value))
.collect(Collectors.joining(", "));
return "%s{%s}".formatted(this.type.getSimpleName(), metaString);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@

package org.dockbox.hartshorn.inject;

import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Set;
import java.util.stream.Collectors;

import org.dockbox.hartshorn.inject.annotations.Initialize;
import org.dockbox.hartshorn.inject.annotations.Priority;
import org.dockbox.hartshorn.inject.annotations.Qualifier;
Expand All @@ -38,6 +33,10 @@
import org.dockbox.hartshorn.util.introspect.view.TypeView;
import org.dockbox.hartshorn.util.option.Option;

import java.util.Collection;
import java.util.Set;
import java.util.stream.Collectors;

/**
* A {@link ComponentKeyResolver} that resolves the {@link ComponentKey} of a component based on the
* presence of annotations on the component type. The key is resolved as follows:
Expand Down Expand Up @@ -114,8 +113,7 @@ protected void configureQualifiers(ComponentKey.Builder<?> builder, ElementAnnot
* @return the resolved qualifiers
*/
protected Set<QualifierKey<?>> resolveQualifiers(ElementAnnotationsIntrospector annotations) {
Set<Annotation> metaQualifiers = annotations.annotedWith(Qualifier.class);
return metaQualifiers.stream()
return annotations.annotedWith(Qualifier.class).stream()
.map(QualifierKey::of)
.collect(Collectors.toSet());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright 2019-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.dockbox.hartshorn.inject.annotations;

import org.dockbox.hartshorn.properties.ListProperty;
import org.dockbox.hartshorn.properties.ObjectProperty;
import org.dockbox.hartshorn.properties.ValueProperty;
import org.dockbox.hartshorn.util.introspect.annotations.Extends;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Indicates that the annotated field or parameter should be injected with a value from the {@link
* org.dockbox.hartshorn.properties.PropertyRegistry}. If no value is found, the {@link PropertyValue#defaultValue()} is used.
*
* <p>Properties in the property registry may have been obtained from various sources, such as configuration files or
* environment variables. The {@link PropertyValue} annotation is a convenient way to inject these values into components.
* Alternatively, the {@link org.dockbox.hartshorn.properties.PropertyRegistry} can be used directly to obtain values.
*
* <p>Parameters with literal {@link ValueProperty}, {@link ListProperty}, or {@link ObjectProperty} types will be
* resolved directly from the registry. Other types will be resolved in their raw form from the property registry, and
* will be converted by the {@link org.dockbox.hartshorn.util.introspect.convert.ConversionService}.
*
* <p>For example, the following code snippet demonstrates how to inject a property into a component:
* <pre>{@code
* @Component
* public class MyComponent {
*
* @Value(name = "sample.message", defaultValue = "Hello world!")
* private String message;
*
* @Value(name = "sample.enum", defaultValue = "FIRST")
* private SampleEnum enumValue;
* }}</pre>
*
* @since 0.7.0
*
* @author Guus Lieben
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Extends(Inject.class)
public @interface PropertyValue {

/**
* The name of the property to inject. If no property with this name is found, the {@link PropertyValue#defaultValue()} is
* used.
*
* @return the name of the property to inject
*/
String name();

/**
* The default value to use if no property with the name {@link PropertyValue#name()} is found.
*
* @return the default value to use
*/
String defaultValue() default "";
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@

package org.dockbox.hartshorn.inject.annotations;

import org.dockbox.hartshorn.inject.QualifierKey;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.dockbox.hartshorn.inject.QualifierKey;

/**
* Meta annotation to mark annotations as qualifiers. Qualifier annotations allow for the creation of
* multiple bindings for the same type, which can be distinguished by the qualifier annotation and potential
Expand All @@ -32,7 +32,7 @@
* that allows you to bind different implementations for each version:
*
* <pre>{@code
* @MetaQualifier
* @Qualifier
* @Retention(RetentionPolicy.RUNTIME)
* @Target(...)
* public @interface VersionQualifier {
Expand Down
Loading
Loading