Skip to content

Commit 52b0531

Browse files
authored
Improve @FrankDocGroup annotation (#175)
1 parent bde2232 commit 52b0531

File tree

52 files changed

+304
-279
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+304
-279
lines changed

frank-doc-doclet/README.md

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ The XML schema helps Frank developers when they are writing their configs, but t
2626

2727
![webapp-intro](./picturesForReadme/webapp-intro.jpg)
2828

29-
To the top-left, you see a list of groups (number 1). These groups are controlled by Java annotation [@FrankDocGroup](https://github.com/ibissource/iaf/blob/master/iaf-commons/src/main/java/nl/nn/adapterframework/doc/FrankDocGroup.java). To the bottom-left, you see the Java class names that are members of the chosen group (number 2). When you select a class name, you get information about it (number 3). More explanation of this text follows later.
29+
To the top-left, you see a list of groups (number 1). These groups are controlled by Java annotation [@FrankDocGroup](https://github.com/frankframework/frankframework/blob/master/commons/src/main/java/org/frankframework/doc/FrankDocGroup.java). To the bottom-left, you see the Java class names that are members of the chosen group (number 2). When you select a class name, you get information about it (number 3). More explanation of this text follows later.
3030

3131
## Descriptions of classes, child elements and attributes
3232

@@ -100,33 +100,15 @@ Frank configs that violate the preferred order can still be parsed by the Frank!
100100

101101
## Groups in the web application
102102

103-
This section is about the groups shown in the top-left of the Frank!Doc web application:
103+
This section is about the groups shown in the top-left of the Frank!Doc web application. These groups are managed through Java annotation [@FrankDocGroup](https://github.com/frankframework/frankframework/blob/master/commons/src/main/java/org/frankframework/doc/FrankDocGroup.java). This annotation has a value field that is of an enum type. Each value of the enum should be annotated with [@EnumLabel](https://github.com/frankframework/frankframework/blob/master/commons/src/main/java/org/frankframework/doc/EnumLabel.java) to provide the group name to be shown. The order of the enum constants determines the order of the shown groups.
104104

105-
![webapp-groups-batch](./picturesForReadme/webapp-groups-batch.jpg)
105+
When [@FrankDocGroup](https://github.com/frankframework/frankframework/blob/master/commons/src/main/java/org/frankframework/doc/FrankDocGroup.java) is placed on a Java class or interface, then all Java classes that implement the interface (or only the class itself in case of a class) are added to the group.
106106

107-
The overview of all groups is shown as number 1. We have selected group `Batch` (number 2). How does the Frank!Doc know the order of the groups and the elements they contain? First, see the following snippet of [IRecordHandlerManager](https://github.com/ibissource/iaf/blob/master/core/src/main/java/nl/nn/adapterframework/batch/IRecordHandlerManager.java)
107+
Java classes that do not have or inherit a [@FrankDocGroup](https://github.com/frankframework/frankframework/blob/master/commons/src/main/java/org/frankframework/doc/FrankDocGroup.java) annotation are put in group `Other`.
108108

109-
![eclipseIRecordHandlerManager](./picturesForReadme/eclipseIRecordHandlerManager.jpg)
109+
A [@FrankDocGroup](https://github.com/frankframework/frankframework/blob/master/commons/src/main/java/org/frankframework/doc/FrankDocGroup.java) annotation is only processed when it appears on a class or interface that appears as the argument of a config child setter. This means: when it gives rise to an [ElementType](src/main/java/org/frankframework/frankdoc/model/ElementType.java).
110110

111-
The interface has a Java annotation [@FrankDocGroup](https://github.com/ibissource/iaf/blob/master/iaf-commons/src/main/java/nl/nn/adapterframework/doc/FrankDocGroup.java). The annotation has fields `name` and `order`. The `order` is an integer that is used to sort the groups in the shown order.
112-
113-
When [@FrankDocGroup](https://github.com/ibissource/iaf/blob/master/iaf-commons/src/main/java/nl/nn/adapterframework/doc/FrankDocGroup.java) is placed on a Java class or interface, then all Java classes that implement the interface (or only the class itself in case of a class) are added to the group. Here is the type hierarchy of [IRecordHandlerManager](https://github.com/ibissource/iaf/blob/master/core/src/main/java/nl/nn/adapterframework/batch/IRecordHandlerManager.java):
114-
115-
![eclipseTypeHierarchyIRecordHandlerManager](./picturesForReadme/eclipseTypeHierarchyIRecordHandlerManager.jpg)
116-
117-
The Java classes that implement [IRecordHandlerManager](https://github.com/ibissource/iaf/blob/master/core/src/main/java/nl/nn/adapterframework/batch/IRecordHandlerManager.java) are highlighted. They are annotated in the first figure of this section as number 3.
118-
119-
The annotation on [IRecordHandlerManager](https://github.com/ibissource/iaf/blob/master/core/src/main/java/nl/nn/adapterframework/batch/IRecordHandlerManager.java) only adds three classes to group `Batch`. The other elements are added by other [@FrankDocGroup](https://github.com/ibissource/iaf/blob/master/iaf-commons/src/main/java/nl/nn/adapterframework/doc/FrankDocGroup.java) annotations. These do not have their `order` field set, see for example [RecordHandlingFlow](https://github.com/ibissource/iaf/blob/master/core/src/main/java/nl/nn/adapterframework/batch/RecordHandlingFlow.java)
120-
121-
![eclipseRecordHandlingFlow](./picturesForReadme/eclipseRecordHandlingFlow.jpg)
122-
123-
The annotation is placed on a class here. Then that class is added to the group in the Frank!Doc web application.
124-
125-
Java classes that do not have or inherit a [@FrankDocGroup](https://github.com/ibissource/iaf/blob/master/iaf-commons/src/main/java/nl/nn/adapterframework/doc/FrankDocGroup.java) annotation are put in group `Other`.
126-
127-
A [@FrankDocGroup](https://github.com/ibissource/iaf/blob/master/iaf-commons/src/main/java/nl/nn/adapterframework/doc/FrankDocGroup.java) annotation is only processed when it appears on a class or interface that appears as the argument of a config child setter. This means: when it gives rise to an [ElementType](src/main/java/org/frankframework/frankdoc/model/ElementType.java).
128-
129-
A Java class can extend a Java class or inherit an interface without a functional meaning. For example, class [MessageStoreSender](https://github.com/ibissource/iaf/blob/master/core/src/main/java/nl/nn/adapterframework/jdbc/MessageStoreSender.java) inherits `ITransactionalStorage`, but that has no functional meaning. Frank configs should not contain elements `MessageStoreSenderMessageLog` or `MessageStoreSenderErrorStorage`. This can be achieved by setting Java annotation `@ExcludeFromType` or JavaDoc tag `@ff.excludeFromType`. Both can take a list of classes as the argument. In case of the JavaDoc tag, do not add `.class` to a class name and separate the classes by a `,`. This annotation is inherited.
111+
A Java class can extend a Java class or inherit an interface without a functional meaning. For example, class [MessageStoreSender](https://github.com/frankframework/frankframework/blob/master/core/src/main/java/org/frankframework/jdbc/MessageStoreSender.java) inherits `ITransactionalStorage`, but that has no functional meaning. Frank configs should not contain elements `MessageStoreSenderMessageLog` or `MessageStoreSenderErrorStorage`. This can be achieved by setting Java annotation `@ExcludeFromType` or JavaDoc tag `@ff.excludeFromType`. Both can take a list of classes as the argument. In case of the JavaDoc tag, do not add `.class` to a class name and separate the classes by a `,`. This annotation is inherited.
130112

131113
## Attribute types
132114

@@ -282,4 +264,4 @@ The default value is `org.frankframework.pipes.SenderPipe` in this example. The
282264

283265
**@ff.reintroduce:** JavaDoc tag that does the same as Java annotation `@Reintroduce`.
284266

285-
**@Label:** Java annotation that appears on other Java annotations, e.g <code>@Category</code>. A target annotation that is itself annotated with meta-annotation `@Label` produces a label in the Frank!Doc webapp when it is applied above a class of the Frank!Framework sources. The value of the label comes from the `value()` field of the target annotation. The name of the label comes from the `@Label` meta-annotation within the definition of the target annotation; attribute `name`. Labels only apply to classes, not child elements and not attributes. You can have enum-valued label values. In this case, the @EnumLabel annotation is supported. The JSON file that feeds the Frank!Doc webapp provides for each label an overview of all possible values. The label values are sorted alphabetically for non-enum values. Enum values are sorted by the order in the enum type.
267+
**@Label:** Java annotation that appears on other Java annotations, e.g <code>@Category</code>. A target annotation that is itself annotated with meta-annotation `@Label` produces a label in the Frank!Doc webapp when it is applied above a class of the Frank!Framework sources. The value of the label comes from the `value()` field of the target annotation. The name of the label comes from the `@Label` meta-annotation within the definition of the target annotation; attribute `name`. Labels only apply to classes, not child elements and not attributes. You can have enum-valued label values. In this case, the @EnumLabel annotation is supported. The JSON file that feeds the Frank!Doc webapp provides for each label an overview of all possible values. The label values are sorted alphabetically. If values are of an enum type, the order of the enum constants is NOT used.
-28.4 KB
Binary file not shown.
-17.9 KB
Binary file not shown.
-20.7 KB
Binary file not shown.
-77.2 KB
Binary file not shown.
Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
1-
/*
2-
Copyright 2021, 2022 WeAreFrank!
1+
/*
2+
Copyright 2021, 2022, 2024 WeAreFrank!
33
4-
Licensed under the Apache License, Version 2.0 (the "License");
5-
you may not use this file except in compliance with the License.
6-
You may obtain a copy of the License at
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
77
8-
http://www.apache.org/licenses/LICENSE-2.0
8+
http://www.apache.org/licenses/LICENSE-2.0
99
10-
Unless required by applicable law or agreed to in writing, software
11-
distributed under the License is distributed on an "AS IS" BASIS,
12-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
See the License for the specific language governing permissions and
14-
limitations under the License.
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
1515
*/
1616

1717
package org.frankframework.frankdoc;
1818

1919
public class Constants {
2020
static final String MODULE_ELEMENT_NAME = "Module";
2121
static final String MODULE_ELEMENT_DESCRIPTION = "Wrapper element to help split up large configuration files into smaller valid XML files. It may be used as root tag when an XML file contains multiple adapters and/or jobs. The Module element itself does not influence the behavior of Frank configurations.";
22+
public static final String FRANK_DOC_GROUP_VALUES_PACKAGE = "org.frankframework.doc.";
2223
}

frank-doc-doclet/src/main/java/org/frankframework/frankdoc/model/FrankDocGroupFactory.java

Lines changed: 41 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright 2021 WeAreFrank!
2+
Copyright 2021, 2024 WeAreFrank!
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -16,71 +16,78 @@
1616

1717
package org.frankframework.frankdoc.model;
1818

19+
import lombok.NonNull;
1920
import org.apache.logging.log4j.Logger;
2021
import org.frankframework.frankdoc.util.LogUtil;
2122
import org.frankframework.frankdoc.wrapper.FrankAnnotation;
2223
import org.frankframework.frankdoc.wrapper.FrankClass;
24+
import org.frankframework.frankdoc.wrapper.FrankClassRepository;
2325
import org.frankframework.frankdoc.wrapper.FrankDocException;
26+
import org.frankframework.frankdoc.wrapper.FrankEnumConstant;
2427

2528
import java.util.ArrayList;
2629
import java.util.Collections;
2730
import java.util.HashMap;
2831
import java.util.List;
2932
import java.util.Map;
33+
import java.util.Optional;
34+
35+
import static org.frankframework.frankdoc.Constants.FRANK_DOC_GROUP_VALUES_PACKAGE;
3036

3137
class FrankDocGroupFactory {
3238
static final String JAVADOC_GROUP_ANNOTATION = "org.frankframework.doc.FrankDocGroup";
39+
static final String FRANK_DOC_GROUP_VALUES_CLASS = FRANK_DOC_GROUP_VALUES_PACKAGE + "FrankDocGroupValue";
40+
private static final Logger log = LogUtil.getLogger(FrankDocGroupFactory.class);
3341

34-
private static Logger log = LogUtil.getLogger(FrankDocGroupFactory.class);
35-
42+
private final Map<String, Integer> valuePositions = new HashMap<>();
3643
private final Map<String, FrankDocGroup> allGroups = new HashMap<>();
3744

3845
// This constructor ensures that group Other is always created, also if there
3946
// is no ElementType without a FrankDocGroup annotation. We always need group
4047
// Other because it will contain Configuration and Module.
41-
FrankDocGroupFactory() {
48+
FrankDocGroupFactory(@NonNull FrankClassRepository classes) {
49+
try {
50+
FrankClass valuesEnum = classes.findClass(FRANK_DOC_GROUP_VALUES_CLASS);
51+
if(valuesEnum == null) {
52+
log.error("Class [{}] has not been loaded", FRANK_DOC_GROUP_VALUES_CLASS);
53+
}
54+
int position = 0;
55+
for(FrankEnumConstant enumConstant: valuesEnum.getEnumConstants()) {
56+
valuePositions.put(enumConstant.getName(), position++);
57+
}
58+
} catch(FrankDocException e) {
59+
log.error("Cannot find value class {} for @FrankDocGroup", FRANK_DOC_GROUP_VALUES_CLASS);
60+
}
4261
FrankDocGroup groupOther = new FrankDocGroup(FrankDocGroup.GROUP_NAME_OTHER);
4362
allGroups.put(groupOther.getName(), groupOther);
4463
}
4564

4665
FrankDocGroup getGroup(FrankClass clazz) {
47-
FrankDocGroup result;
4866
try {
4967
FrankAnnotation annotation = clazz.getAnnotationIncludingInherited(JAVADOC_GROUP_ANNOTATION);
5068
if(annotation == null) {
51-
result = getGroup(FrankDocGroup.GROUP_NAME_OTHER);
69+
log.trace("Class [{}] belongs to group [{}]", () -> clazz.getName(), () -> FrankDocGroup.GROUP_NAME_OTHER);
70+
return allGroups.get(FrankDocGroup.GROUP_NAME_OTHER);
5271
} else {
53-
String groupName = (String) annotation.getValueOf("name");
54-
Integer groupOrder = (Integer) annotation.getValueOf("order");
55-
log.trace("FrankDocGroup requested for group name {} with new order {}", () -> groupName, () -> groupOrder);
56-
result = getGroup(groupName, groupOrder);
72+
FrankEnumConstant enumConstant = (FrankEnumConstant) annotation.getValue();
73+
String groupName = new EnumValue(enumConstant).getLabel();
74+
if(allGroups.containsKey(groupName)) {
75+
FrankDocGroup group = allGroups.get(groupName);
76+
log.trace("Class [{}] belongs to found group [{}]", () -> clazz.getName(), () -> group.getName());
77+
return group;
78+
} else {
79+
int groupOrder = Optional.of(valuePositions.get(enumConstant.getName())).orElseThrow(
80+
() -> new FrankDocException("Programming error: Could not get position of enum constant " + enumConstant.getName(), null));
81+
FrankDocGroup group = new FrankDocGroup(groupName);
82+
group.setOrder(groupOrder);
83+
log.trace("Class [{}] belongs to new group [{}], order is [{}]", () -> clazz.getName(), () -> group.getName(), () -> group.getOrder());
84+
allGroups.put(groupName, group);
85+
return group;
86+
}
5787
}
5888
} catch(FrankDocException e) {
5989
log.error("Class [{}] has invalid @FrankDocGroup: {}", clazz.getName(), e.getMessage());
60-
return getGroup(FrankDocGroup.GROUP_NAME_OTHER);
61-
}
62-
return result;
63-
}
64-
65-
FrankDocGroup getGroup(String groupName, Integer groupOrder) {
66-
FrankDocGroup result;
67-
result = getGroup(groupName);
68-
if(groupOrder == null) {
69-
// The Doclet API does not provide the default value of the @FrankDocGroup annotation.
70-
// We need to repeat it here.
71-
groupOrder = Integer.MAX_VALUE;
72-
}
73-
result.setOrder(groupOrder);
74-
return result;
75-
}
76-
77-
private FrankDocGroup getGroup(String name) {
78-
if(allGroups.containsKey(name)) {
79-
return allGroups.get(name);
80-
} else {
81-
FrankDocGroup group = new FrankDocGroup(name);
82-
allGroups.put(name, group);
83-
return group;
90+
return allGroups.get(FrankDocGroup.GROUP_NAME_OTHER);
8491
}
8592
}
8693

frank-doc-doclet/src/main/java/org/frankframework/frankdoc/model/FrankDocModel.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright 2020 - 2023 WeAreFrank!
2+
Copyright 2020 - 2024 WeAreFrank!
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -64,7 +64,7 @@ public class FrankDocModel {
6464

6565
private final @Getter Map<String, List<ConfigChildSetterDescriptor>> configChildDescriptors = new HashMap<>();
6666

67-
private final FrankDocGroupFactory groupFactory = new FrankDocGroupFactory();
67+
private final FrankDocGroupFactory groupFactory;
6868
private @Getter List<FrankDocGroup> groups;
6969

7070
// We want to iterate FrankElement in the order they are created, to be able
@@ -86,6 +86,7 @@ public class FrankDocModel {
8686

8787
FrankDocModel(FrankClassRepository classRepository, String rootClassName) {
8888
this.classRepository = classRepository;
89+
this.groupFactory = new FrankDocGroupFactory(classRepository);
8990
this.rootClassName = rootClassName;
9091
}
9192

frank-doc-doclet/src/main/java/org/frankframework/frankdoc/model/FrankElement.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright 2020 - 2023 WeAreFrank!
2+
Copyright 2020 - 2024 WeAreFrank!
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -254,7 +254,7 @@ void handleSpecificLabel(FrankAnnotation labelAddingAnnotation, LabelValues labe
254254
// This considers annotation @EnumLabel
255255
EnumValue value = new EnumValue(enumConstant);
256256
labels.add(new FrankLabel(label, value.getLabel()));
257-
labelValues.addEnumValue(label, value.getLabel(), enumConstant.getPosition());
257+
labelValues.addValue(label, value.getLabel());
258258
} else {
259259
labels.add(new FrankLabel(label, rawValue.toString()));
260260
labelValues.addValue(label, rawValue.toString());

frank-doc-doclet/src/main/java/org/frankframework/frankdoc/model/LabelValues.java

Lines changed: 3 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright 2022 WeAreFrank!
2+
Copyright 2022, 2024 WeAreFrank!
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -30,62 +30,11 @@
3030
public class LabelValues {
3131
private static final Logger log = LogUtil.getLogger(LabelValues.class);
3232

33-
private abstract static class SortableValue implements Comparable<SortableValue> {
34-
private @Getter final String value;
35-
36-
SortableValue(String value) {
37-
this.value = value;
38-
}
39-
40-
@Override
41-
public String toString() {
42-
return value;
43-
}
44-
}
45-
46-
private static final class EnumValue extends SortableValue {
47-
private final int order;
48-
49-
EnumValue(String value, int order) {
50-
super(value);
51-
this.order = order;
52-
}
53-
54-
@Override
55-
public int compareTo(SortableValue other) {
56-
// It is a programming error if a label has both enum values and
57-
// non-enum values. If this happens, a ClassCastException will occur.
58-
return Integer.compare(order, ((EnumValue) other).order);
59-
}
60-
}
61-
62-
private static final class SimpleValue extends SortableValue {
63-
SimpleValue(String value) {
64-
super(value);
65-
}
66-
67-
@Override
68-
public int compareTo(SortableValue other) {
69-
// It is a programming error if a label has both enum values and
70-
// non-enum values. If this happens, a ClassCastException will occur.
71-
return getValue().compareTo(((SimpleValue) other).getValue());
72-
}
73-
}
74-
7533
private boolean isInitialized = false;
76-
private final Map<String, List<SortableValue>> data = new HashMap<>();
34+
private final Map<String, List<String>> data = new HashMap<>();
7735

7836
void addValue(String label, String value) {
79-
log.trace("Label [{}] can have non-enum value [{}]", label, value);
80-
add(label, new SimpleValue(value));
81-
}
82-
83-
void addEnumValue(String label, String value, int order) {
84-
log.trace("Label [{}] can have enum value [{}], position is [{}]", label, value, order);
85-
add(label, new EnumValue(value, order));
86-
}
87-
88-
private void add(String label, SortableValue value) {
37+
log.trace("Label [{}] can have value [{}]", label, value);
8938
data.putIfAbsent(label, new ArrayList<>());
9039
data.get(label).add(value);
9140
}
@@ -114,7 +63,6 @@ private void checkInitialized() {
11463
List<String> getAllValuesOfLabel(String label) {
11564
checkInitialized();
11665
return data.get(label).stream()
117-
.map(SortableValue::getValue)
11866
.distinct()
11967
.collect(Collectors.toList());
12068
}

0 commit comments

Comments
 (0)