Skip to content

Commit abef750

Browse files
committed
And added even more Javadoc
1 parent f26c4f1 commit abef750

20 files changed

+584
-131
lines changed

spring-boot-python-executor-autoconfigure/src/main/java/io/w4t3rcs/python/condition/AbstractResolverCondition.java

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.w4t3rcs.python.condition;
22

3+
import io.w4t3rcs.python.config.PythonResolverConfiguration;
34
import io.w4t3rcs.python.properties.PythonResolverProperties;
45
import org.springframework.context.annotation.Condition;
56
import org.springframework.context.annotation.ConditionContext;
@@ -9,20 +10,70 @@
910
import java.util.Arrays;
1011
import java.util.Objects;
1112

13+
/**
14+
* Base {@link Condition} implementation that checks for the presence of a specific
15+
* declared Python resolver in the Spring environment configuration.
16+
* <p>
17+
* This condition verifies whether the {@code spring.python.resolver.declared} property
18+
* contains a given resolver identifier (case-insensitive).
19+
* </p>
20+
* <p>
21+
* Implementations must specify the resolver to check by overriding {@link #getDeclaredResolver()}.
22+
* </p>
23+
* <p>
24+
* The property {@code spring.python.resolver.declared} is expected to be a list/array of strings.
25+
* If the property is missing or empty, the condition will not match.
26+
* </p>
27+
*
28+
* @see Condition
29+
* @see PythonResolverProperties.DeclaredResolver
30+
* @see PythonResolverConfiguration
31+
* @author w4t3rcs
32+
* @since 1.0.0
33+
*/
1234
public abstract class AbstractResolverCondition implements Condition {
1335
private static final String SPRING_PYTHON_RESOLVER_DECLARED_PROPERTY = "spring.python.resolver.declared";
1436

37+
/**
38+
* Checks whether the Spring environment contains the configured declared resolver.
39+
* Delegates the check to {@link #matchesByDeclaredResolver(ConditionContext, PythonResolverProperties.DeclaredResolver)}.
40+
*
41+
* @param context the condition context, must not be {@code null}
42+
* @param metadata metadata of the annotated component, ignored in this implementation
43+
* @return {@code true} if the declared resolver is present in the environment property, {@code false} otherwise
44+
*/
1545
@Override
1646
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
1747
return this.matchesByDeclaredResolver(context, this.getDeclaredResolver());
1848
}
1949

20-
public boolean matchesByDeclaredResolver(ConditionContext context, PythonResolverProperties.DeclaredResolver propertyValue) {
50+
/**
51+
* Checks if the specified declared resolver is present in the
52+
* {@code spring.python.resolver.declared} property of the environment.
53+
* <p>
54+
* The property is read as a string array and matched case-insensitively against
55+
* the string representation of the {@code propertyValue} argument.
56+
* </p>
57+
* <p>
58+
* If the property is missing or empty, this method returns {@code false}.
59+
* </p>
60+
*
61+
* @param context the condition context providing access to environment, must not be {@code null}
62+
* @param propertyValue the declared resolver to check for, must not be {@code null}
63+
* @return {@code true} if the declared resolver is found in the property, {@code false} otherwise
64+
*/
65+
protected boolean matchesByDeclaredResolver(ConditionContext context, PythonResolverProperties.DeclaredResolver propertyValue) {
2166
Environment environment = context.getEnvironment();
2267
String[] property = environment.getProperty(SPRING_PYTHON_RESOLVER_DECLARED_PROPERTY, String[].class);
2368
return Arrays.stream(Objects.requireNonNull(property))
2469
.anyMatch(declared -> declared.equals(propertyValue.toString().toLowerCase()));
2570
}
2671

72+
/**
73+
* Returns the {@link PythonResolverProperties.DeclaredResolver} value
74+
* that this condition should match against.
75+
*
76+
* @return the declared resolver to check, never {@code null}
77+
*/
2778
protected abstract PythonResolverProperties.DeclaredResolver getDeclaredResolver();
2879
}

spring-boot-python-executor-autoconfigure/src/main/java/io/w4t3rcs/python/condition/PrintedResultResolverCondition.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,25 @@
11
package io.w4t3rcs.python.condition;
22

3+
import io.w4t3rcs.python.config.PythonResolverConfiguration;
34
import io.w4t3rcs.python.properties.PythonResolverProperties;
45
import lombok.AccessLevel;
56
import lombok.Getter;
67

8+
/**
9+
* {@link AbstractResolverCondition} implementation that checks whether the
10+
* {@link PythonResolverProperties.DeclaredResolver#PRINTED_RESULT} resolver
11+
* is declared in the Spring environment property {@code spring.python.resolver.declared}.
12+
* <p>
13+
* This condition is used to enable components related to printed result processing
14+
* only when the {@code PRINTED_RESULT} resolver is explicitly declared.
15+
* </p>
16+
*
17+
* @see AbstractResolverCondition
18+
* @see PythonResolverProperties.DeclaredResolver#PRINTED_RESULT
19+
* @see PythonResolverConfiguration
20+
* @author w4t3rcs
21+
* @since 1.0.0
22+
*/
723
@Getter(AccessLevel.PROTECTED)
824
public class PrintedResultResolverCondition extends AbstractResolverCondition {
925
private final PythonResolverProperties.DeclaredResolver declaredResolver = PythonResolverProperties.DeclaredResolver.PRINTED_RESULT;

spring-boot-python-executor-autoconfigure/src/main/java/io/w4t3rcs/python/condition/Py4JResolverCondition.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,25 @@
11
package io.w4t3rcs.python.condition;
22

3+
import io.w4t3rcs.python.config.PythonResolverConfiguration;
34
import io.w4t3rcs.python.properties.PythonResolverProperties;
45
import lombok.AccessLevel;
56
import lombok.Getter;
67

8+
/**
9+
* {@link AbstractResolverCondition} implementation that verifies whether the
10+
* {@link PythonResolverProperties.DeclaredResolver#PY4J} resolver
11+
* is declared in the Spring environment property {@code spring.python.resolver.declared}.
12+
* <p>
13+
* This condition controls activation of components related to Py4J integration,
14+
* ensuring they are enabled only when the {@code PY4J} resolver is explicitly declared.
15+
* </p>
16+
*
17+
* @see AbstractResolverCondition
18+
* @see PythonResolverProperties.DeclaredResolver#PY4J
19+
* @see PythonResolverConfiguration
20+
* @author w4t3rcs
21+
* @since 1.0.0
22+
*/
723
@Getter(AccessLevel.PROTECTED)
824
public class Py4JResolverCondition extends AbstractResolverCondition {
925
private final PythonResolverProperties.DeclaredResolver declaredResolver = PythonResolverProperties.DeclaredResolver.PY4J;

spring-boot-python-executor-autoconfigure/src/main/java/io/w4t3rcs/python/condition/RestrictedPythonResolverCondition.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,25 @@
11
package io.w4t3rcs.python.condition;
22

3+
import io.w4t3rcs.python.config.PythonResolverConfiguration;
34
import io.w4t3rcs.python.properties.PythonResolverProperties;
45
import lombok.AccessLevel;
56
import lombok.Getter;
67

8+
/**
9+
* {@link AbstractResolverCondition} implementation that checks whether the
10+
* {@link PythonResolverProperties.DeclaredResolver#RESTRICTED_PYTHON} resolver
11+
* is declared in the Spring environment property {@code spring.python.resolver.declared}.
12+
* <p>
13+
* This condition activates components related to RestrictedPython execution
14+
* only if the {@code RESTRICTED_PYTHON} resolver is explicitly declared.
15+
* </p>
16+
*
17+
* @see AbstractResolverCondition
18+
* @see PythonResolverProperties.DeclaredResolver#RESTRICTED_PYTHON
19+
* @see PythonResolverConfiguration
20+
* @author w4t3rcs
21+
* @since 1.0.0
22+
*/
723
@Getter(AccessLevel.PROTECTED)
824
public class RestrictedPythonResolverCondition extends AbstractResolverCondition {
925
private final PythonResolverProperties.DeclaredResolver declaredResolver = PythonResolverProperties.DeclaredResolver.RESTRICTED_PYTHON;

spring-boot-python-executor-autoconfigure/src/main/java/io/w4t3rcs/python/condition/ResultResolverCondition.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,25 @@
11
package io.w4t3rcs.python.condition;
22

3+
import io.w4t3rcs.python.config.PythonResolverConfiguration;
34
import io.w4t3rcs.python.properties.PythonResolverProperties;
45
import lombok.AccessLevel;
56
import lombok.Getter;
67

8+
/**
9+
* {@link AbstractResolverCondition} implementation that checks whether the
10+
* {@link PythonResolverProperties.DeclaredResolver#RESULT} resolver
11+
* is declared in the Spring environment property {@code spring.python.resolver.declared}.
12+
* <p>
13+
* This condition activates components related to result processing
14+
* only if the {@code RESULT} resolver is explicitly declared.
15+
* </p>
16+
*
17+
* @see AbstractResolverCondition
18+
* @see PythonResolverProperties.DeclaredResolver#RESULT
19+
* @see PythonResolverConfiguration
20+
* @author w4t3rcs
21+
* @since 1.0.0
22+
*/
723
@Getter(AccessLevel.PROTECTED)
824
public class ResultResolverCondition extends AbstractResolverCondition {
925
private final PythonResolverProperties.DeclaredResolver declaredResolver = PythonResolverProperties.DeclaredResolver.RESULT;

spring-boot-python-executor-autoconfigure/src/main/java/io/w4t3rcs/python/condition/SpelythonResolverCondition.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,25 @@
11
package io.w4t3rcs.python.condition;
22

3+
import io.w4t3rcs.python.config.PythonResolverConfiguration;
34
import io.w4t3rcs.python.properties.PythonResolverProperties;
45
import lombok.AccessLevel;
56
import lombok.Getter;
67

8+
/**
9+
* {@link AbstractResolverCondition} implementation that checks whether the
10+
* {@link PythonResolverProperties.DeclaredResolver#SPELYTHON} resolver
11+
* is declared in the Spring environment property {@code spring.python.resolver.declared}.
12+
* <p>
13+
* This condition activates components related to SpEL expression resolution in Python scripts
14+
* only if the {@code SPELYTHON} resolver is explicitly declared.
15+
* </p>
16+
*
17+
* @see AbstractResolverCondition
18+
* @see PythonResolverProperties.DeclaredResolver#SPELYTHON
19+
* @see PythonResolverConfiguration
20+
* @author w4t3rcs
21+
* @since 1.0.0
22+
*/
723
@Getter(AccessLevel.PROTECTED)
824
public class SpelythonResolverCondition extends AbstractResolverCondition {
925
private final PythonResolverProperties.DeclaredResolver declaredResolver = PythonResolverProperties.DeclaredResolver.SPELYTHON;

spring-boot-python-executor-autoconfigure/src/main/java/io/w4t3rcs/python/config/PythonResolverConfiguration.java

Lines changed: 124 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,109 @@
1414
import org.springframework.core.annotation.Order;
1515

1616
import java.util.List;
17-
1817
/**
19-
* Main configuration class for {@link PythonResolver}.
20-
* This class sets up the core infrastructure for {@link PythonResolver} bean declaration.
18+
* Main configuration class for {@link PythonResolver} beans.
19+
* <p>
20+
* This configuration class defines and registers various {@link PythonResolver} implementations
21+
* as Spring beans, each conditionally created based on specific environment properties or
22+
* declared resolver conditions.
23+
* </p>
24+
* <p>
25+
* Each {@link PythonResolver} bean is assigned an order that determines the sequence of
26+
* resolver application when used collectively.
27+
* </p>
28+
* <p>
29+
* The configuration also provides a default {@link PythonResolverHolder} bean implementation
30+
* {@link BasicPythonResolverHolder} if no other {@link PythonResolverHolder} bean is present
31+
* in the Spring context.
32+
* </p>
33+
*
34+
* <pre>{@code
35+
* // Example of enabling the Spelython and Result resolvers via application.properties:
36+
* spring.python.resolver.declared=spelython, result
37+
*
38+
* // Example of enabling the Py4J resolver:
39+
* spring.python.resolver.declared=py4j
40+
* spring.python.py4j.enabled=true
41+
*
42+
* // Example usage of injected PythonResolverHolder in a service:
43+
* @Autowired
44+
* private PythonResolverHolder resolverHolder;
45+
*
46+
* public String executeScript(String script) {
47+
* return resolverHolder.resolveAll(script, Map.of());
48+
* }
49+
* }</pre>
50+
*
51+
* @see PythonResolver
52+
* @see SpelythonResolver
53+
* @see Py4JResolver
54+
* @see RestrictedPythonResolver
55+
* @see ResultResolver
56+
* @see PrintedResultResolver
57+
* @see PythonResolverHolder
58+
* @see BasicPythonResolverHolder
59+
* @see SpelythonResolverCondition
60+
* @see Py4JResolverCondition
61+
* @see RestrictedPythonResolverCondition
62+
* @see ResultResolverCondition
63+
* @see PrintedResultResolverCondition
64+
* @author w4t3rcs
65+
* @since 1.0.0
2166
*/
2267
@Configuration
2368
@EnableConfigurationProperties(PythonResolverProperties.class)
2469
public class PythonResolverConfiguration {
70+
/**
71+
* Order value for {@link SpelythonResolver} bean.
72+
*/
2573
public static final int SPELYTHON_RESOLVER_ORDER = 0;
74+
/**
75+
* Order value for {@link Py4JResolver} bean.
76+
*/
2677
public static final int PY4J_RESOLVER_ORDER = 50;
78+
/**
79+
* Order value for {@link RestrictedPythonResolver} bean.
80+
*/
2781
public static final int RESTRICTED_PYTHON_RESOLVER_ORDER = 100;
82+
/**
83+
* Order value for {@link ResultResolver} bean.
84+
*/
2885
public static final int RESULT_RESOLVER_ORDER = 150;
86+
/**
87+
* Order value for {@link PrintedResultResolver} bean.
88+
*/
2989
public static final int PRINTED_RESULT_RESOLVER_ORDER = 200;
3090

91+
/**
92+
* Creates a {@link SpelythonResolver} bean.
93+
* <p>
94+
* This bean is created only if {@link SpelythonResolverCondition} matches,
95+
* which requires {@code spring.python.resolver.declared} to contain "spelython".
96+
* </p>
97+
*
98+
* @param resolverProperties {@link PythonResolverProperties} bean, must not be null
99+
* @param applicationContext the Spring {@link ApplicationContext}, must not be null
100+
* @param objectMapper Jackson {@link ObjectMapper} bean, must not be null
101+
* @return configured {@link SpelythonResolver} instance, never null
102+
*/
31103
@Bean
32104
@Order(SPELYTHON_RESOLVER_ORDER)
33105
@Conditional(SpelythonResolverCondition.class)
34106
public PythonResolver spelythonResolver(PythonResolverProperties resolverProperties, ApplicationContext applicationContext, ObjectMapper objectMapper) {
35107
return new SpelythonResolver(resolverProperties, applicationContext, objectMapper);
36108
}
37109

110+
/**
111+
* Creates a {@link Py4JResolver} bean.
112+
* <p>
113+
* This bean is created only if {@link Py4JResolverCondition} matches and
114+
* the property {@code spring.python.py4j.enabled} is set to {@code true}.
115+
* </p>
116+
*
117+
* @param resolverProperties {@link PythonResolverProperties} bean, must not be null
118+
* @return configured {@link Py4JResolver} instance, never null
119+
*/
38120
@Bean
39121
@Order(PY4J_RESOLVER_ORDER)
40122
@Conditional(Py4JResolverCondition.class)
@@ -43,28 +125,66 @@ public PythonResolver py4JResolver(PythonResolverProperties resolverProperties)
43125
return new Py4JResolver(resolverProperties);
44126
}
45127

128+
/**
129+
* Creates a {@link RestrictedPythonResolver} bean.
130+
* <p>
131+
* This bean is created only if {@link RestrictedPythonResolverCondition} matches,
132+
* which requires {@code spring.python.resolver.declared} to contain "restricted_python".
133+
* </p>
134+
*
135+
* @param resolverProperties {@link PythonResolverProperties} bean, must not be null
136+
* @return configured {@link RestrictedPythonResolver} instance, never null
137+
*/
46138
@Bean
47139
@Order(RESTRICTED_PYTHON_RESOLVER_ORDER)
48140
@Conditional(RestrictedPythonResolverCondition.class)
49141
public PythonResolver restrictedPythonResolver(PythonResolverProperties resolverProperties) {
50142
return new RestrictedPythonResolver(resolverProperties);
51143
}
52144

145+
/**
146+
* Creates a {@link ResultResolver} bean.
147+
* <p>
148+
* This bean is created only if {@link ResultResolverCondition} matches,
149+
* which requires {@code spring.python.resolver.declared} to contain "result".
150+
* </p>
151+
*
152+
* @param resolverProperties {@link PythonResolverProperties} bean, must not be null
153+
* @return configured {@link ResultResolver} instance, never null
154+
*/
53155
@Bean
54156
@Order(RESULT_RESOLVER_ORDER)
55157
@Conditional(ResultResolverCondition.class)
56158
public PythonResolver resultResolver(PythonResolverProperties resolverProperties) {
57159
return new ResultResolver(resolverProperties);
58160
}
59161

162+
/**
163+
* Creates a {@link PrintedResultResolver} bean.
164+
* <p>
165+
* This bean is created only if {@link ResultResolverCondition} matches,
166+
* which requires {@code spring.python.resolver.declared} to contain "printed_result".
167+
* </p>
168+
*
169+
* @param resolverProperties {@link PythonResolverProperties} bean, must not be null
170+
* @return configured {@link PrintedResultResolver} instance, never null
171+
*/
60172
@Bean
61173
@Order(PRINTED_RESULT_RESOLVER_ORDER)
62174
@Conditional(PrintedResultResolverCondition.class)
63-
@ConditionalOnProperty(name = "spring.python.executor.type", havingValue = "local")
64175
public PythonResolver printedResultResolver(PythonResolverProperties resolverProperties) {
65176
return new PrintedResultResolver(resolverProperties);
66177
}
67178

179+
/**
180+
* Creates the default {@link PythonResolverHolder} bean if none is defined.
181+
* <p>
182+
* This holder aggregates all available {@link PythonResolver} beans in the context.
183+
* </p>
184+
*
185+
* @param pythonResolvers list of all registered {@link PythonResolver} beans, never null but can be empty
186+
* @return a {@link BasicPythonResolverHolder} instance containing the given resolvers, never null
187+
*/
68188
@Bean
69189
@ConditionalOnMissingBean(PythonResolverHolder.class)
70190
public PythonResolverHolder basicPythonResolverHolder(List<PythonResolver> pythonResolvers) {

0 commit comments

Comments
 (0)