Skip to content

Commit

Permalink
feat: enable trimming of white spaces before and after an annotation.
Browse files Browse the repository at this point in the history
  • Loading branch information
credmond-git committed Oct 31, 2024
1 parent 28de4b6 commit 0efdfa7
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,12 @@ public class GestaltBuilder {
// Token that represents the closing of a string substitution.
private String annotationClosingToken = null;

// regex used to extract the annotation
private String annotationRegex = null;

// trim the white space before and after an annotation.
private Boolean annotationTrimWhiteSpace = null;

// the maximum nested substitution depth.
private Integer maxSubstitutionNestedDepth = null;

Expand Down Expand Up @@ -1276,6 +1280,17 @@ public GestaltBuilder setAnnotationRegex(String annotationRegex) {
return this;
}

/**
* Set if we trim the white space before and after an annotation.
*
* @param annotationTrimWhiteSpace trim the white space before and after an annotation.
* @return the builder
*/
public GestaltBuilder setAnnotationTrimWhiteSpace(Boolean annotationTrimWhiteSpace) {
this.annotationTrimWhiteSpace = annotationTrimWhiteSpace;
return this;
}

/**
* Get the maximum string substitution nested depth.
* If you have nested or recursive substitutions that go deeper than this it will fail.
Expand Down Expand Up @@ -1734,6 +1749,9 @@ private GestaltConfig rebuildConfig() {
newConfig.setAnnotationClosingToken(Objects.requireNonNullElseGet(annotationClosingToken,
() -> gestaltConfig.getAnnotationClosingToken()));

newConfig.setAnnotationTrimWhiteSpace(Objects.requireNonNullElseGet(annotationTrimWhiteSpace,
() -> gestaltConfig.getAnnotationTrimWhiteSpace()));

newConfig.setAnnotationRegex(Objects.requireNonNullElseGet(annotationRegex,
() -> gestaltConfig.getAnnotationRegex()));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ public class GestaltConfig {
private String annotationOpeningToken = "@{";
// Token that represents the closing of an annotation.
private String annotationClosingToken = "}";
// trim the white space before and after an annotation.
private Boolean annotationTrimWhiteSpace = true;
// the regex used to parse annotations.
// Must have a named capture group annotation, and parameter, where the annotation is required and the parameter is optional.
private String annotationRegex = AnnotationConfigNodeProcessor.DEFAULT_ANNOTATION_REGEX;
Expand Down Expand Up @@ -326,6 +328,24 @@ public void setAnnotationClosingToken(String annotationClosingToken) {
this.annotationClosingToken = annotationClosingToken;
}

/**
* trim the white space before and after an annotation.
*
* @return trim the white space before and after an annotation.
*/
public Boolean getAnnotationTrimWhiteSpace() {
return annotationTrimWhiteSpace;
}

/**
* Set if we trim the white space before and after an annotation.
*
* @param annotationTrimWhiteSpace trim the white space before and after an annotation.
*/
public void setAnnotationTrimWhiteSpace(Boolean annotationTrimWhiteSpace) {
this.annotationTrimWhiteSpace = annotationTrimWhiteSpace;
}

/**
* Get the regex for annotation processing.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class AnnotationConfigNodeProcessor implements ConfigNodeProcessor {
private int openingTokenSize = openingToken.length();
private int closingTokenSize = closingToken.length();
private Pattern pattern = Pattern.compile(DEFAULT_ANNOTATION_REGEX);
private boolean annotationTrimWhiteSpace = true;

public AnnotationConfigNodeProcessor() {
ServiceLoader<AnnotationMetadataTransform> loader = ServiceLoader.load(AnnotationMetadataTransform.class);
Expand All @@ -51,6 +52,8 @@ public void applyConfig(ConfigNodeProcessorConfig config) {
this.closingTokenSize = closingToken.length();

this.pattern = Pattern.compile(config.getConfig().getAnnotationRegex());

this.annotationTrimWhiteSpace = config.getConfig().getAnnotationTrimWhiteSpace();
}

@Override
Expand Down Expand Up @@ -98,7 +101,13 @@ public GResultOf<ConfigNode> process(String path, ConfigNode currentNode) {
errors.addAll(metadata.getErrors());
metadataMap.putAll(metadata.results());
// remove the found annotation
leafValue = leafValue.substring(0, annotationLocation) + leafValue.substring(annotationClosing + closingTokenSize);
if (annotationTrimWhiteSpace) {
leafValue = leafValue.substring(0, annotationLocation).stripTrailing() +
leafValue.substring(annotationClosing + closingTokenSize).stripLeading();
} else {
leafValue = leafValue.substring(0, annotationLocation) +
leafValue.substring(annotationClosing + closingTokenSize);
}
foundAnnotation = true;
} else {
errors.add(new ValidationError.UnknownAnnotation(path, annotation));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,58 @@ public void testNoCacheAnnotationViaObservability() throws GestaltException {
Assertions.assertFalse(metricsRecorder.metrics.containsKey("cache.hit"));
}

@Test
public void testNoCacheAnnotationTrim() throws GestaltException {

Map<String, String> configs = new HashMap<>();
configs.put("db.password", "test");
configs.put("db.port", "123");
configs.put("db.uri", "my.sql @{noCache} .com");

var metricsRecorder = new TestObservationRecorder(0);

Gestalt gestalt = new GestaltBuilder()
.addSource(MapConfigSourceBuilder.builder().setCustomConfig(configs).build())
.setObservationsRecorders(List.of(metricsRecorder))
.setObservationsEnabled(true)
.setAnnotationTrimWhiteSpace(true)
.build();

gestalt.loadConfigs();


Assertions.assertEquals("my.sql.com", gestalt.getConfig("db", DBInfo.class).getUri());
Assertions.assertEquals("my.sql.com", gestalt.getConfig("db", DBInfo.class).getUri());
// there should be no cache hits.
Assertions.assertFalse(metricsRecorder.metrics.containsKey("cache.hit"));
}

@Test
public void testNoCacheAnnotationNoTrim() throws GestaltException {

Map<String, String> configs = new HashMap<>();
configs.put("db.password", "test");
configs.put("db.port", "123");
configs.put("db.uri", "my.sql @{noCache} .com");

var metricsRecorder = new TestObservationRecorder(0);

Gestalt gestalt = new GestaltBuilder()
.addSource(MapConfigSourceBuilder.builder().setCustomConfig(configs).build())
.setObservationsRecorders(List.of(metricsRecorder))
.setObservationsEnabled(true)
.setAnnotationTrimWhiteSpace(false)
.build();

gestalt.loadConfigs();


Assertions.assertEquals("my.sql .com", gestalt.getConfig("db", DBInfo.class).getUri());
Assertions.assertEquals("my.sql .com", gestalt.getConfig("db", DBInfo.class).getUri());
// there should be no cache hits.
Assertions.assertFalse(metricsRecorder.metrics.containsKey("cache.hit"));
}

@Test
public void testNoCacheAnnotationObjectViaObservability() throws GestaltException {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ public void build() throws GestaltException {
.setAnnotationOpeningToken("@{")
.setAnnotationClosingToken("}")
.setAnnotationRegex("^(?<annotation>\\w+):?(?<key>.+?)?$")
.setAnnotationTrimWhiteSpace(true)
.setMaxSubstitutionNestedDepth(5)
.setSubstitutionRegex("")
.setGestaltConfig(new GestaltConfig())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,46 @@ public void testAnnotationSingleMiddle() {
Assertions.assertTrue((boolean) result.results().getMetadata().get(IsNoCacheMetadata.NO_CACHE).get(0).getMetadata());
}

@Test
public void testAnnotationSingleMiddleWhitespace() {
LeafNode node = new LeafNode("hel @{test} lo");

AnnotationConfigNodeProcessor annotationConfigNodeProcessor =
new AnnotationConfigNodeProcessor(List.of(new TestAnnotationMetadataTransform()));

var result = annotationConfigNodeProcessor.process("my.data", node);
Assertions.assertTrue(result.hasResults());
Assertions.assertFalse(result.hasErrors());
Assertions.assertEquals("hello", result.results().getValue().get());

Assertions.assertTrue(result.results().getMetadata().containsKey(IsNoCacheMetadata.NO_CACHE));
Assertions.assertTrue((boolean) result.results().getMetadata().get(IsNoCacheMetadata.NO_CACHE).get(0).getMetadata());
}

@Test
public void testAnnotationSingleMiddleDontTrimWhitespace() {
LeafNode node = new LeafNode("hel @{test} lo");

GestaltConfig gestaltConfig = new GestaltConfig();
gestaltConfig.setAnnotationTrimWhiteSpace(false);

ConfigNodeProcessorConfig configNodeProcessorConfig =
new ConfigNodeProcessorConfig(gestaltConfig, null, null, null, null);

AnnotationConfigNodeProcessor annotationConfigNodeProcessor =
new AnnotationConfigNodeProcessor(List.of(new TestAnnotationMetadataTransform()));

annotationConfigNodeProcessor.applyConfig(configNodeProcessorConfig);

var result = annotationConfigNodeProcessor.process("my.data", node);
Assertions.assertTrue(result.hasResults());
Assertions.assertFalse(result.hasErrors());
Assertions.assertEquals("hel lo", result.results().getValue().get());

Assertions.assertTrue(result.results().getMetadata().containsKey(IsNoCacheMetadata.NO_CACHE));
Assertions.assertTrue((boolean) result.results().getMetadata().get(IsNoCacheMetadata.NO_CACHE).get(0).getMetadata());
}

@Test
public void testAnnotationSingleParameter() {
LeafNode node = new LeafNode("hello@{test:true}");
Expand Down

0 comments on commit 0efdfa7

Please sign in to comment.