Add spotbugs & pmd for static analysis
Also move internal state validation into DoSomethingProvider since that sits in test code
This commit is contained in:
parent
df1a083398
commit
efc1c048b6
56
pom.xml
56
pom.xml
|
|
@ -54,6 +54,13 @@
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<!-- used so that lombok can generate suppressions for spotbugs. It needs to find it on the relevant classpath -->
|
||||||
|
<groupId>com.github.spotbugs</groupId>
|
||||||
|
<artifactId>spotbugs</artifactId>
|
||||||
|
<version>4.7.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
<artifactId>slf4j-api</artifactId>
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
|
@ -132,6 +139,7 @@
|
||||||
</argLine>
|
</argLine>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-failsafe-plugin</artifactId>
|
<artifactId>maven-failsafe-plugin</artifactId>
|
||||||
|
|
@ -263,6 +271,54 @@
|
||||||
</plugin>
|
</plugin>
|
||||||
<!-- end sign -->
|
<!-- end sign -->
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-pmd-plugin</artifactId>
|
||||||
|
<version>3.13.0</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>run-pmd</id>
|
||||||
|
<phase>verify</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>check</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.github.spotbugs</groupId>
|
||||||
|
<artifactId>spotbugs-maven-plugin</artifactId>
|
||||||
|
<version>4.7.0.0</version>
|
||||||
|
<configuration>
|
||||||
|
<excludeFilterFile>spotbugs-exclusions.xml</excludeFilterFile>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.h3xstream.findsecbugs</groupId>
|
||||||
|
<artifactId>findsecbugs-plugin</artifactId>
|
||||||
|
<version>1.12.0</version>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</configuration>
|
||||||
|
<dependencies>
|
||||||
|
<!-- overwrite dependency on spotbugs if you want to specify the version of spotbugs -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.spotbugs</groupId>
|
||||||
|
<artifactId>spotbugs</artifactId>
|
||||||
|
<version>4.7.1</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>run-spotbugs</id>
|
||||||
|
<phase>verify</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>check</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<FindBugsFilter
|
||||||
|
xmlns="https://github.com/spotbugs/filter/3.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="https://github.com/spotbugs/filter/3.0.0 https://raw.githubusercontent.com/spotbugs/spotbugs/3.1.0/spotbugs/etc/findbugsfilter.xsd">
|
||||||
|
|
||||||
|
<!-- I'm reasonably confident that the singleton pattern isn't exposing internal representation -->
|
||||||
|
<And>
|
||||||
|
<Class name="dev.openfeature.javasdk.OpenFeatureAPI"/>
|
||||||
|
<Bug pattern="MS_EXPOSE_REP"/>
|
||||||
|
</And>
|
||||||
|
<!-- similarly, client using the singleton doesn't seem bad -->
|
||||||
|
<And>
|
||||||
|
<Class name="dev.openfeature.javasdk.OpenFeatureClient"/>
|
||||||
|
<Bug pattern="EI_EXPOSE_REP2"/>
|
||||||
|
</And>
|
||||||
|
|
||||||
|
<!-- Test class that should be excluded -->
|
||||||
|
<Match>
|
||||||
|
<Class name="dev.openfeature.javasdk.DoSomethingProvider"/>
|
||||||
|
</Match>
|
||||||
|
<!-- All bugs in test classes, except for JUnit-specific bugs -->
|
||||||
|
<Match>
|
||||||
|
<Class name="~.*\.*Test" />
|
||||||
|
<Not>
|
||||||
|
<Bug code="IJU" />
|
||||||
|
</Not>
|
||||||
|
</Match>
|
||||||
|
</FindBugsFilter>
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
lombok.addLombokGeneratedAnnotation = true
|
lombok.addLombokGeneratedAnnotation = true
|
||||||
|
lombok.extern.findbugs.addSuppressFBWarnings = true
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import java.util.Map;
|
||||||
@SuppressWarnings("PMD.BeanMembersShouldSerialize")
|
@SuppressWarnings("PMD.BeanMembersShouldSerialize")
|
||||||
public class EvaluationContext {
|
public class EvaluationContext {
|
||||||
@Setter @Getter private String targetingKey;
|
@Setter @Getter private String targetingKey;
|
||||||
private final Map<String, dev.openfeature.javasdk.internal.Pair<FlagValueType, Object>> attributes;
|
private final Map<String, Pair<FlagValueType, Object>> attributes;
|
||||||
|
|
||||||
public EvaluationContext() {
|
public EvaluationContext() {
|
||||||
this.targetingKey = "";
|
this.targetingKey = "";
|
||||||
|
|
|
||||||
|
|
@ -4,5 +4,5 @@ package dev.openfeature.javasdk;
|
||||||
* Holds identifying information about a given entity
|
* Holds identifying information about a given entity
|
||||||
*/
|
*/
|
||||||
public interface Metadata {
|
public interface Metadata {
|
||||||
public String getName();
|
String getName();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,6 @@ public class NoOpProvider implements FeatureProvider {
|
||||||
public static final String PASSED_IN_DEFAULT = "Passed in default";
|
public static final String PASSED_IN_DEFAULT = "Passed in default";
|
||||||
@Getter
|
@Getter
|
||||||
private final String name = "No-op Provider";
|
private final String name = "No-op Provider";
|
||||||
private EvaluationContext ctx;
|
|
||||||
|
|
||||||
public EvaluationContext getMergedContext() {
|
|
||||||
return ctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Metadata getMetadata() {
|
public Metadata getMetadata() {
|
||||||
return new Metadata() {
|
return new Metadata() {
|
||||||
|
|
@ -27,7 +21,6 @@ public class NoOpProvider implements FeatureProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProviderEvaluation<Boolean> getBooleanEvaluation(String key, Boolean defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
|
public ProviderEvaluation<Boolean> getBooleanEvaluation(String key, Boolean defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
|
||||||
this.ctx = ctx;
|
|
||||||
return ProviderEvaluation.<Boolean>builder()
|
return ProviderEvaluation.<Boolean>builder()
|
||||||
.value(defaultValue)
|
.value(defaultValue)
|
||||||
.variant(PASSED_IN_DEFAULT)
|
.variant(PASSED_IN_DEFAULT)
|
||||||
|
|
@ -37,7 +30,6 @@ public class NoOpProvider implements FeatureProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProviderEvaluation<String> getStringEvaluation(String key, String defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
|
public ProviderEvaluation<String> getStringEvaluation(String key, String defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
|
||||||
this.ctx = ctx;
|
|
||||||
return ProviderEvaluation.<String>builder()
|
return ProviderEvaluation.<String>builder()
|
||||||
.value(defaultValue)
|
.value(defaultValue)
|
||||||
.variant(PASSED_IN_DEFAULT)
|
.variant(PASSED_IN_DEFAULT)
|
||||||
|
|
@ -47,7 +39,6 @@ public class NoOpProvider implements FeatureProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProviderEvaluation<Integer> getIntegerEvaluation(String key, Integer defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
|
public ProviderEvaluation<Integer> getIntegerEvaluation(String key, Integer defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
|
||||||
this.ctx = ctx;
|
|
||||||
return ProviderEvaluation.<Integer>builder()
|
return ProviderEvaluation.<Integer>builder()
|
||||||
.value(defaultValue)
|
.value(defaultValue)
|
||||||
.variant(PASSED_IN_DEFAULT)
|
.variant(PASSED_IN_DEFAULT)
|
||||||
|
|
@ -56,7 +47,6 @@ public class NoOpProvider implements FeatureProvider {
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public ProviderEvaluation<Double> getDoubleEvaluation(String key, Double defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
|
public ProviderEvaluation<Double> getDoubleEvaluation(String key, Double defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
|
||||||
this.ctx = ctx;
|
|
||||||
return ProviderEvaluation.<Double>builder()
|
return ProviderEvaluation.<Double>builder()
|
||||||
.value(defaultValue)
|
.value(defaultValue)
|
||||||
.variant(PASSED_IN_DEFAULT)
|
.variant(PASSED_IN_DEFAULT)
|
||||||
|
|
@ -65,7 +55,6 @@ public class NoOpProvider implements FeatureProvider {
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public <T> ProviderEvaluation<T> getObjectEvaluation(String key, T defaultValue, EvaluationContext invocationContext, FlagEvaluationOptions options) {
|
public <T> ProviderEvaluation<T> getObjectEvaluation(String key, T defaultValue, EvaluationContext invocationContext, FlagEvaluationOptions options) {
|
||||||
this.ctx = ctx;
|
|
||||||
return ProviderEvaluation.<T>builder()
|
return ProviderEvaluation.<T>builder()
|
||||||
.value(defaultValue)
|
.value(defaultValue)
|
||||||
.variant(PASSED_IN_DEFAULT)
|
.variant(PASSED_IN_DEFAULT)
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,6 @@ import lombok.experimental.StandardException;
|
||||||
|
|
||||||
@StandardException
|
@StandardException
|
||||||
public class FlagNotFoundError extends OpenFeatureError {
|
public class FlagNotFoundError extends OpenFeatureError {
|
||||||
private static long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
@Getter private final ErrorCode errorCode = ErrorCode.GENERAL;
|
@Getter private final ErrorCode errorCode = ErrorCode.GENERAL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,6 @@ import lombok.experimental.StandardException;
|
||||||
|
|
||||||
@StandardException
|
@StandardException
|
||||||
public class GeneralError extends OpenFeatureError{
|
public class GeneralError extends OpenFeatureError{
|
||||||
private static long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
@Getter private final ErrorCode errorCode = ErrorCode.GENERAL;
|
@Getter private final ErrorCode errorCode = ErrorCode.GENERAL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,6 @@ import lombok.experimental.StandardException;
|
||||||
|
|
||||||
@StandardException
|
@StandardException
|
||||||
public abstract class OpenFeatureError extends RuntimeException {
|
public abstract class OpenFeatureError extends RuntimeException {
|
||||||
private static long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
public abstract ErrorCode getErrorCode();
|
public abstract ErrorCode getErrorCode();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import lombok.experimental.StandardException;
|
||||||
|
|
||||||
@StandardException
|
@StandardException
|
||||||
public class ParseError extends OpenFeatureError {
|
public class ParseError extends OpenFeatureError {
|
||||||
private static long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Getter private final ErrorCode errorCode = ErrorCode.PARSE_ERROR;
|
@Getter private final ErrorCode errorCode = ErrorCode.PARSE_ERROR;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import lombok.experimental.StandardException;
|
||||||
|
|
||||||
@StandardException
|
@StandardException
|
||||||
public class TypeMismatchError extends OpenFeatureError {
|
public class TypeMismatchError extends OpenFeatureError {
|
||||||
private static long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Getter private final ErrorCode errorCode = ErrorCode.TYPE_MISMATCH;
|
@Getter private final ErrorCode errorCode = ErrorCode.TYPE_MISMATCH;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,12 @@ package dev.openfeature.javasdk;
|
||||||
|
|
||||||
public class DoSomethingProvider implements FeatureProvider {
|
public class DoSomethingProvider implements FeatureProvider {
|
||||||
|
|
||||||
|
private EvaluationContext savedContext;
|
||||||
|
|
||||||
|
public EvaluationContext getMergedContext() {
|
||||||
|
return savedContext;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Metadata getMetadata() {
|
public Metadata getMetadata() {
|
||||||
return () -> "test";
|
return () -> "test";
|
||||||
|
|
@ -9,6 +15,7 @@ public class DoSomethingProvider implements FeatureProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProviderEvaluation<Boolean> getBooleanEvaluation(String key, Boolean defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
|
public ProviderEvaluation<Boolean> getBooleanEvaluation(String key, Boolean defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
|
||||||
|
savedContext = ctx;
|
||||||
return ProviderEvaluation.<Boolean>builder()
|
return ProviderEvaluation.<Boolean>builder()
|
||||||
.value(!defaultValue).build();
|
.value(!defaultValue).build();
|
||||||
}
|
}
|
||||||
|
|
@ -22,6 +29,7 @@ public class DoSomethingProvider implements FeatureProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProviderEvaluation<Integer> getIntegerEvaluation(String key, Integer defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
|
public ProviderEvaluation<Integer> getIntegerEvaluation(String key, Integer defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
|
||||||
|
savedContext = ctx;
|
||||||
return ProviderEvaluation.<Integer>builder()
|
return ProviderEvaluation.<Integer>builder()
|
||||||
.value(defaultValue * 100)
|
.value(defaultValue * 100)
|
||||||
.build();
|
.build();
|
||||||
|
|
@ -29,6 +37,7 @@ public class DoSomethingProvider implements FeatureProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProviderEvaluation<Double> getDoubleEvaluation(String key, Double defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
|
public ProviderEvaluation<Double> getDoubleEvaluation(String key, Double defaultValue, EvaluationContext ctx, FlagEvaluationOptions options) {
|
||||||
|
savedContext = ctx;
|
||||||
return ProviderEvaluation.<Double>builder()
|
return ProviderEvaluation.<Double>builder()
|
||||||
.value(defaultValue * 100)
|
.value(defaultValue * 100)
|
||||||
.build();
|
.build();
|
||||||
|
|
@ -36,6 +45,7 @@ public class DoSomethingProvider implements FeatureProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> ProviderEvaluation<T> getObjectEvaluation(String key, T defaultValue, EvaluationContext invocationContext, FlagEvaluationOptions options) {
|
public <T> ProviderEvaluation<T> getObjectEvaluation(String key, T defaultValue, EvaluationContext invocationContext, FlagEvaluationOptions options) {
|
||||||
|
savedContext = invocationContext;
|
||||||
return ProviderEvaluation.<T>builder()
|
return ProviderEvaluation.<T>builder()
|
||||||
.value(null)
|
.value(null)
|
||||||
.build();
|
.build();
|
||||||
|
|
|
||||||
|
|
@ -218,7 +218,7 @@ class FlagEvaluationSpecTest implements HookFixtures {
|
||||||
@Specification(number="3.2.2", text="Evaluation context MUST be merged in the order: API (global) - client - invocation, with duplicate values being overwritten.")
|
@Specification(number="3.2.2", text="Evaluation context MUST be merged in the order: API (global) - client - invocation, with duplicate values being overwritten.")
|
||||||
@Test void multi_layer_context_merges_correctly() {
|
@Test void multi_layer_context_merges_correctly() {
|
||||||
OpenFeatureAPI api = OpenFeatureAPI.getInstance();
|
OpenFeatureAPI api = OpenFeatureAPI.getInstance();
|
||||||
NoOpProvider provider = new NoOpProvider();
|
DoSomethingProvider provider = new DoSomethingProvider();
|
||||||
api.setProvider(provider);
|
api.setProvider(provider);
|
||||||
|
|
||||||
EvaluationContext apiCtx = new EvaluationContext();
|
EvaluationContext apiCtx = new EvaluationContext();
|
||||||
|
|
@ -238,7 +238,8 @@ class FlagEvaluationSpecTest implements HookFixtures {
|
||||||
clientCtx.addStringAttribute("common", "5");
|
clientCtx.addStringAttribute("common", "5");
|
||||||
clientCtx.addStringAttribute("invocation", "6");
|
clientCtx.addStringAttribute("invocation", "6");
|
||||||
|
|
||||||
assertFalse(c.getBooleanValue("key", false, invocationCtx));
|
// dosomethingprovider inverts this value.
|
||||||
|
assertTrue(c.getBooleanValue("key", false, invocationCtx));
|
||||||
|
|
||||||
EvaluationContext merged = provider.getMergedContext();
|
EvaluationContext merged = provider.getMergedContext();
|
||||||
assertEquals("6", merged.getStringAttribute("invocation"));
|
assertEquals("6", merged.getStringAttribute("invocation"));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue