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

Fix value substitution for parameters and forwards #194

Merged
merged 3 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2020 - 2023 WeAreFrank!
Copyright 2020 - 2024 WeAreFrank!

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -72,8 +72,8 @@ public final class Utils {
private static final String JAVA_SHORT = "java.lang.Short";

private static final String JAVADOC_LINK_START_DELIMITER = "{@link";
private static final String JAVADOC_VALUE_START_DELIMITER = "{@value";
private static final String JAVADOC_SUBSTITUTION_PATTERN_STOP_DELIMITER = "}";
public static final String JAVADOC_VALUE_START_DELIMITER = "{@value";
public static final String JAVADOC_SUBSTITUTION_PATTERN_STOP_DELIMITER = "}";

private static Map<String, String> primitiveToBoxed = new HashMap<>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,11 @@ void handleAncestorMethod(FrankClass ancestorClass) {
}

private void handlePossibleParameters(FrankClass clazz) {
this.meaningOfParameters = clazz.getJavaDocTag(JAVADOC_PARAMETERS);
try {
this.meaningOfParameters = Utils.replaceClassFieldValue(clazz.getJavaDocTag(JAVADOC_PARAMETERS), clazz);
} catch(FrankDocException e) {
log.error("Error parsing the meaning of parameters", e);
}
assembleParsedJavaDocTags(clazz, JAVADOC_PARAMETER, p -> this.specificParameters.add(p));
}

Expand All @@ -221,7 +225,7 @@ private void assembleParsedJavaDocTags(FrankClass clazz, String tagName, Consume
for (String arguments : clazz.getAllJavaDocTagsOf(tagName)) {
ParsedJavaDocTag parsed;
try {
parsed = ParsedJavaDocTag.getInstance(arguments);
parsed = ParsedJavaDocTag.getInstance(arguments, s -> Utils.replaceClassFieldValue(s, clazz));
} catch (FrankDocException e) {
log.error("Error parsing a [{}] tag of class [{}]", tagName, fullName, e);
continue;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2021 WeAreFrank!
Copyright 2021, 2024 WeAreFrank!

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand All @@ -19,29 +19,42 @@
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.frankframework.frankdoc.Utils;
import org.frankframework.frankdoc.util.FrankDocThrowingFunction;
import org.frankframework.frankdoc.util.LogUtil;
import org.frankframework.frankdoc.wrapper.FrankDocException;

import java.util.Arrays;
import java.util.List;
import java.util.function.Function;

public class ParsedJavaDocTag {
private static Logger log = LogUtil.getLogger(ParsedJavaDocTag.class);
private static final Logger log = LogUtil.getLogger(ParsedJavaDocTag.class);

private static final String QUOTE = "\"";

private final @Getter String name;
private final @Getter String description;

static ParsedJavaDocTag getInstance(String javaDocTagParameter) throws FrankDocException {
static ParsedJavaDocTag getInstance(String javaDocTagParameter, FrankDocThrowingFunction valueSubstitutor) throws FrankDocException {
if(StringUtils.isAllBlank(javaDocTagParameter)) {
throw new FrankDocException("Tag has no arguments", null);
}
ParsedJavaDocTag raw = null;
// The doclet API already trimmed the argument. We do not have to care about leading spaces.
if(javaDocTagParameter.startsWith(QUOTE)) {
return getInstanceQuoteDelimited(javaDocTagParameter);
raw = getInstanceQuoteDelimited(javaDocTagParameter);
} else {
raw = getInstanceSpaceDelimited(javaDocTagParameter);
}
if (raw.description == null) {
return new ParsedJavaDocTag(valueSubstitutor.apply(raw.name), null);
} else {
return new ParsedJavaDocTag(valueSubstitutor.apply(raw.name), valueSubstitutor.apply(raw.description));
}
return getInstanceSpaceDelimited(javaDocTagParameter);
}

private static ParsedJavaDocTag getInstanceQuoteDelimited(String javaDocTagParameter) {
private static ParsedJavaDocTag getInstanceQuoteDelimited(String javaDocTagParameter) throws FrankDocException {
int startQuoteIdx = javaDocTagParameter.indexOf(QUOTE);
int endQuoteIdx = javaDocTagParameter.indexOf(QUOTE, startQuoteIdx+1);
if(endQuoteIdx < 0) {
Expand All @@ -56,8 +69,8 @@ private static ParsedJavaDocTag getInstanceQuoteDelimited(String javaDocTagParam
return new ParsedJavaDocTag(name, description);
}

private static ParsedJavaDocTag getInstanceSpaceDelimited(String javaDocTagParameter) {
int idx = javaDocTagParameter.indexOf(" ");
private static ParsedJavaDocTag getInstanceSpaceDelimited(String javaDocTagParameter) throws FrankDocException {
int idx = ParsedJavaDocTag.getNameDescriptionSplitIndex(javaDocTagParameter);
if(idx < 0) {
return new ParsedJavaDocTag(javaDocTagParameter, null);
}
Expand All @@ -69,6 +82,39 @@ private static ParsedJavaDocTag getInstanceSpaceDelimited(String javaDocTagParam
return new ParsedJavaDocTag(name, description);
}

private static int getNameDescriptionSplitIndex(String javadocTagParameter) throws FrankDocException {
int idx = 0;
while (idx < javadocTagParameter.length()) {
idx = ParsedJavaDocTag.getIndexFirstMatchFromIndex(javadocTagParameter, idx, " ", Utils.JAVADOC_VALUE_START_DELIMITER);
if (idx < 0) {
// Not found
return idx;
}
if (javadocTagParameter.charAt(idx) == ' ') {
// Found the first space
return idx;
}
// We do not have the space that splits the name and the description, but a {@value ... } pattern
// Skip that.
idx = javadocTagParameter.indexOf(Utils.JAVADOC_SUBSTITUTION_PATTERN_STOP_DELIMITER, idx);
if (idx == -1) {
throw new FrankDocException(String.format("Value substitution pattern %s not finished by %s",
Utils.JAVADOC_VALUE_START_DELIMITER,
Utils.JAVADOC_SUBSTITUTION_PATTERN_STOP_DELIMITER), null);
}
idx = idx + 1;
}
return -1;
}

private static int getIndexFirstMatchFromIndex(String subject, int fromIndex, String ...searchItemsArg) {
List<String> searchItems = Arrays.asList(searchItemsArg);
return searchItems.stream().map(item -> subject.indexOf(item, fromIndex))
.filter(i -> i >= 0)
.min(Integer::compare)
.orElse(-1);
}

private ParsedJavaDocTag(String name, String description) {
this.name = name;
this.description = description;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
Copyright 2024 WeAreFrank!

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

http://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.frankframework.frankdoc.util;

import org.frankframework.frankdoc.wrapper.FrankDocException;

@FunctionalInterface
public interface FrankDocThrowingFunction {
String apply(String value) throws FrankDocException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ public static Collection<Object[]> data() {
{XsdVersion.STRICT, AttributeTypeStrategy.ALLOW_PROPERTY_REF, "general-test-digester-rules.xml", "org.frankframework.frankdoc.testtarget.examples.labels.Master", null, "labels.json"},
{XsdVersion.STRICT, AttributeTypeStrategy.ALLOW_PROPERTY_REF, "general-test-digester-rules.xml", "org.frankframework.frankdoc.testtarget.examples.exclude.from.type.Master", "excludeFromType.xsd", "excludeFromType.json"},
{XsdVersion.STRICT, AttributeTypeStrategy.ALLOW_PROPERTY_REF, "general-test-digester-rules.xml", "org.frankframework.frankdoc.testtarget.packageprivate.override.Child", "child.xsd", null},
{XsdVersion.STRICT, AttributeTypeStrategy.ALLOW_PROPERTY_REF, "general-test-digester-rules.xml", "org.frankframework.frankdoc.testtarget.featurepackage.Documented", "documented.xsd", "documented.json"}
{XsdVersion.STRICT, AttributeTypeStrategy.ALLOW_PROPERTY_REF, "general-test-digester-rules.xml", "org.frankframework.frankdoc.testtarget.featurepackage.Documented", "documented.xsd", "documented.json"},
{XsdVersion.STRICT, AttributeTypeStrategy.ALLOW_PROPERTY_REF, "general-test-digester-rules.xml", "org.frankframework.frankdoc.testtarget.examples.valueSubs.WithValueSubstitutions", "valueSubs.xsd", "valueSubs.json"}
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,46 +7,50 @@
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;

/**
* We do not test substituting \{@value \... \} in these tests. That would require
* FrankClass objects, which would make this test too complicated.
*/
public class ParsedJavaDocTagTest {
@Test
public void whenParamTagHasNoSpaceThenOnlyName() throws Exception {
ParsedJavaDocTag p = ParsedJavaDocTag.getInstance("myName");
ParsedJavaDocTag p = ParsedJavaDocTag.getInstance("myName", s -> s);
assertNull(p.getDescription());
assertEquals("myName", p.getName());
}

@Test
public void whenParamTagHasSpacesAfterNameThenStillDescriptionNull() throws Exception {
ParsedJavaDocTag p = ParsedJavaDocTag.getInstance("myName ");
ParsedJavaDocTag p = ParsedJavaDocTag.getInstance("myName ", s -> s);
assertNull(p.getDescription());
assertEquals("myName", p.getName());
}

@Test
public void whenParamTagHasMultipleWordsThenNameAndDescription() throws Exception {
ParsedJavaDocTag p = ParsedJavaDocTag.getInstance("myName Description ");
ParsedJavaDocTag p = ParsedJavaDocTag.getInstance("myName Description ", s -> s);
assertEquals("myName", p.getName());
assertEquals("Description", p.getDescription());
}

@Test
public void whenAnnotationValueStartsWithQuoteThenNameIsStringUntilEndQuote() throws Exception {
ParsedJavaDocTag p = ParsedJavaDocTag.getInstance("\"My quoted name\" Description");
ParsedJavaDocTag p = ParsedJavaDocTag.getInstance("\"My quoted name\" Description", s -> s);
assertEquals("My quoted name", p.getName());
assertEquals("Description", p.getDescription());
}

@Test
public void whenQuotedForwardNameIsEmptyStringAndDescriptionRightAfterLastQuoteThenNoError() throws Exception {
ParsedJavaDocTag p = ParsedJavaDocTag.getInstance("\"\"Description");
ParsedJavaDocTag p = ParsedJavaDocTag.getInstance("\"\"Description", s -> s);
assertEquals("", p.getName());
assertEquals("Description", p.getDescription());
}

@Test
public void whenJavaDocHasNoParametersThenError() throws Exception {
assertThrows(FrankDocException.class, () -> {
ParsedJavaDocTag.getInstance("");
ParsedJavaDocTag.getInstance("", s -> s);
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.frankframework.frankdoc.testtarget.examples.valueSubs;

/**
* In the class description, we substitute {@value WithValueSubstitutions#MY_CONSTANT}
*
* @ff.parameters In the text that defines the meaning of parameters, we substitute {@value WithValueSubstitutions#MY_CONSTANT}
*
* @ff.parameter {@value WithValueSubstitutions#MY_CONSTANT} Description of this parameter is {@value WithValueSubstitutions#MY_CONSTANT}
*
* @ff.forward {@value WithValueSubstitutions#MY_CONSTANT} Forward description {@value WithValueSubstitutions#MY_CONSTANT}
*/
public class Other {

/**
* Attribute description that cites {@value WithValueSubstitutions#MY_CONSTANT}
* @param value
*/
public void setMyAttribute(String value) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.frankframework.frankdoc.testtarget.examples.valueSubs;

/**
* In the class description, we substitute {@value #MY_CONSTANT}
*
* @ff.parameters In the text that defines the meaning of parameters, we substitute {@value #MY_CONSTANT}
*
* @ff.parameter {@value #MY_CONSTANT} Description of this parameter is {@value #MY_CONSTANT}
*
* @ff.forward {@value #MY_CONSTANT} Forward description {@value #MY_CONSTANT}
*/
public class WithValueSubstitutions {
public static final String MY_CONSTANT = "my-constant";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Je hebt nu alleen testen voor substutions binnen de zelfde class. Misschien dat je ook nog een testje zou kunnen maken van een andere class (duplicaat hiervan) die verwijst naar MY_CONSTANT.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gedaan.


/**
* In an attribute description, we substitute {@value #MY_CONSTANT}
*/
public void setMyAttribute(String value) {
}

public void registerA(Other child) {
}
}
Loading
Loading