diff --git a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/JavaDocParser.java b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/JavaDocParser.java
index 6f5d8bf6c23a8..f8f6ee9283aba 100644
--- a/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/JavaDocParser.java
+++ b/core/processor/src/main/java/io/quarkus/annotation/processor/generate_doc/JavaDocParser.java
@@ -52,6 +52,8 @@ final class JavaDocParser {
private static final String ORDERED_LIST_NODE = "ol";
private static final String SUPER_SCRIPT_NODE = "sup";
private static final String UN_ORDERED_LIST_NODE = "ul";
+ private static final String PREFORMATED_NODE = "pre";
+ private static final String BLOCKQUOTE_NODE = "blockquote";
private static final String BIG_ASCIDOC_STYLE = "[.big]";
private static final String LINK_ATTRIBUTE_FORMAT = "[%s]";
@@ -62,6 +64,10 @@ final class JavaDocParser {
private static final String UNORDERED_LIST_ITEM_ASCIDOC_STYLE = " - ";
private static final String UNDERLINE_ASCIDOC_STYLE = "[.underline]";
private static final String LINE_THROUGH_ASCIDOC_STYLE = "[.line-through]";
+ private static final String HARD_LINE_BREAK_ASCIDOC_STYLE = " +\n";
+ private static final String CODE_BLOCK_ASCIDOC_STYLE = "```";
+ private static final String BLOCKQUOTE_BLOCK_ASCIDOC_STYLE = "[quote]\n____";
+ private static final String BLOCKQUOTE_BLOCK_ASCIDOC_STYLE_END = "____";
private final boolean inlineMacroMode;
@@ -185,25 +191,51 @@ private String htmlJavadocToAsciidoc(JavadocDescription javadocDescription) {
}
}
- return sb.toString().trim();
+ return trim(sb);
}
private void appendHtml(StringBuilder sb, Node node) {
for (Node childNode : node.childNodes()) {
switch (childNode.nodeName()) {
case PARAGRAPH_NODE:
- sb.append(NEW_LINE);
+ newLine(sb);
+ newLine(sb);
appendHtml(sb, childNode);
break;
+ case PREFORMATED_NODE:
+ newLine(sb);
+ newLine(sb);
+ sb.append(CODE_BLOCK_ASCIDOC_STYLE);
+ newLine(sb);
+ for (Node grandChildNode : childNode.childNodes()) {
+ unescapeHtmlEntities(sb, grandChildNode.toString());
+ }
+ newLineIfNeeded(sb);
+ sb.append(CODE_BLOCK_ASCIDOC_STYLE);
+ newLine(sb);
+ newLine(sb);
+ break;
+ case BLOCKQUOTE_NODE:
+ newLine(sb);
+ newLine(sb);
+ sb.append(BLOCKQUOTE_BLOCK_ASCIDOC_STYLE);
+ newLine(sb);
+ appendHtml(sb, childNode);
+ newLineIfNeeded(sb);
+ sb.append(BLOCKQUOTE_BLOCK_ASCIDOC_STYLE_END);
+ newLine(sb);
+ newLine(sb);
+ break;
case ORDERED_LIST_NODE:
case UN_ORDERED_LIST_NODE:
+ newLine(sb);
appendHtml(sb, childNode);
break;
case LIST_ITEM_NODE:
final String marker = childNode.parent().nodeName().equals(ORDERED_LIST_NODE)
? ORDERED_LIST_ITEM_ASCIDOC_STYLE
: UNORDERED_LIST_ITEM_ASCIDOC_STYLE;
- sb.append(NEW_LINE);
+ newLine(sb);
sb.append(marker);
appendHtml(sb, childNode);
break;
@@ -213,7 +245,7 @@ private void appendHtml(StringBuilder sb, Node node) {
sb.append(link);
final StringBuilder caption = new StringBuilder();
appendHtml(caption, childNode);
- sb.append(String.format(LINK_ATTRIBUTE_FORMAT, caption.toString().trim()));
+ sb.append(String.format(LINK_ATTRIBUTE_FORMAT, trim(caption)));
break;
case CODE_NODE:
sb.append(BACKTICK);
@@ -269,7 +301,7 @@ private void appendHtml(StringBuilder sb, Node node) {
sb.append(HASH);
break;
case NEW_LINE_NODE:
- sb.append(NEW_LINE);
+ sb.append(HARD_LINE_BREAK_ASCIDOC_STYLE);
break;
case TEXT_NODE:
String text = ((TextNode) childNode).text();
@@ -295,6 +327,142 @@ private void appendHtml(StringBuilder sb, Node node) {
}
}
+ /**
+ * Trim the content of the given {@link StringBuilder} holding also AsciiDoc had line break {@code " +\n"}
+ * for whitespace in addition to characters <= {@code ' '}.
+ *
+ * @param sb the {@link StringBuilder} to trim
+ * @return the trimmed content of the given {@link StringBuilder}
+ */
+ static String trim(StringBuilder sb) {
+ int length = sb.length();
+ int offset = 0;
+ while (offset < length) {
+ final char ch = sb.charAt(offset);
+ if (ch == ' '
+ && offset + 2 < length
+ && sb.charAt(offset + 1) == '+'
+ && sb.charAt(offset + 2) == '\n') {
+ /* Space followed by + and newline is AsciiDoc hard break that we consider whitespace */
+ offset += 3;
+ continue;
+ } else if (ch > ' ') {
+ /* Non-whitespace as defined by String.trim() */
+ break;
+ }
+ offset++;
+ }
+ if (offset > 0) {
+ sb.delete(0, offset);
+ }
+ if (sb.length() > 0) {
+ offset = sb.length() - 1;
+ while (offset >= 0) {
+ final char ch = sb.charAt(offset);
+ if (ch == '\n'
+ && offset - 2 >= 0
+ && sb.charAt(offset - 1) == '+'
+ && sb.charAt(offset - 2) == ' ') {
+ /* Space followed by + is AsciiDoc hard break that we consider whitespace */
+ offset -= 3;
+ continue;
+ } else if (ch > ' ') {
+ /* Non-whitespace as defined by String.trim() */
+ break;
+ }
+ offset--;
+ }
+ if (offset < sb.length() - 1) {
+ sb.setLength(offset + 1);
+ }
+ }
+ return sb.toString();
+ }
+
+ private static StringBuilder newLineIfNeeded(StringBuilder sb) {
+ trimText(sb, " \t\r\n");
+ return sb.append(NEW_LINE);
+ }
+
+ private static StringBuilder newLine(StringBuilder sb) {
+ /* Trim trailing spaces and tabs at the end of line */
+ trimText(sb, " \t");
+ return sb.append(NEW_LINE);
+ }
+
+ private static StringBuilder trimText(StringBuilder sb, String charsToTrim) {
+ while (sb.length() > 0 && charsToTrim.indexOf(sb.charAt(sb.length() - 1)) >= 0) {
+ sb.setLength(sb.length() - 1);
+ }
+ return sb;
+ }
+
+ private StringBuilder unescapeHtmlEntities(StringBuilder sb, String text) {
+ int i = 0;
+ /* trim leading whitespace */
+ LOOP: while (i < text.length()) {
+ switch (text.charAt(i++)) {
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ break;
+ default:
+ i--;
+ break LOOP;
+ }
+ }
+ for (; i < text.length(); i++) {
+ final char ch = text.charAt(i);
+ switch (ch) {
+ case '&':
+ int start = ++i;
+ while (i < text.length() && text.charAt(i) != ';') {
+ i++;
+ }
+ if (i > start) {
+ final String abbrev = text.substring(start, i);
+ switch (abbrev) {
+ case "lt":
+ sb.append('<');
+ break;
+ case "gt":
+ sb.append('>');
+ break;
+ case "nbsp":
+ sb.append("{nbsp}");
+ break;
+ case "amp":
+ sb.append('&');
+ break;
+ default:
+ try {
+ int code = Integer.parseInt(abbrev);
+ sb.append((char) code);
+ } catch (NumberFormatException e) {
+ throw new RuntimeException(
+ "Could not parse HTML entity &" + abbrev + "; in\n\n" + text + "\n\n");
+ }
+ break;
+ }
+ }
+ break;
+ case '\r':
+ if (i + 1 < text.length() && text.charAt(i + 1) == '\n') {
+ /* Ignore \r followed by \n */
+ } else {
+ /* A Mac single \r: replace by \n */
+ sb.append('\n');
+ }
+ break;
+ default:
+ sb.append(ch);
+
+ }
+ }
+ return sb;
+ }
+
private StringBuilder appendEscapedAsciiDoc(StringBuilder sb, String text) {
boolean escaping = false;
for (int i = 0; i < text.length(); i++) {
diff --git a/core/processor/src/test/java/io/quarkus/annotation/processor/generate_doc/JavaDocConfigDescriptionParserTest.java b/core/processor/src/test/java/io/quarkus/annotation/processor/generate_doc/JavaDocConfigDescriptionParserTest.java
index 5410b7f7bdc91..f23705f230e63 100644
--- a/core/processor/src/test/java/io/quarkus/annotation/processor/generate_doc/JavaDocConfigDescriptionParserTest.java
+++ b/core/processor/src/test/java/io/quarkus/annotation/processor/generate_doc/JavaDocConfigDescriptionParserTest.java
@@ -28,7 +28,7 @@ public void parseNullJavaDoc() {
@Test
public void removeParagraphIndentation() {
String parsed = parser.parseConfigDescription("First paragraph
Second Paragraph");
- assertEquals("First paragraph\n\nSecond Paragraph", parsed);
+ assertEquals("First paragraph +\n +\nSecond Paragraph", parsed);
}
@Test
@@ -50,13 +50,13 @@ public void parseSimpleJavaDoc() {
@Test
public void parseJavaDocWithParagraph() {
String javaDoc = "hello
world
"; - String expectedOutput = "hello\nworld"; + String expectedOutput = "hello\n\nworld"; String parsed = parser.parseConfigDescription(javaDoc); assertEquals(expectedOutput, parsed); javaDoc = "hello worldbonjour
le monde
"; - expectedOutput = "hello world\nbonjour \nle monde"; + expectedOutput = "hello world\n\nbonjour\n\nle monde"; parsed = parser.parseConfigDescription(javaDoc); assertEquals(expectedOutput, parsed); @@ -118,21 +118,6 @@ public void parseJavaDocWithStyles() { assertEquals(expectedOutput, parsed); } - @Test - public void parseJavaDocWithUlTags() { - String javaDoc = "hello\n" + + "In sub types (be it sub classes/interfaces or interface implementations), no parameter constraints may\n" + + "be declared on overridden or implemented methods, nor may parameters be marked for cascaded validation.\n" + + "This would pose a strengthening of preconditions to be fulfilled by the caller.\n" + + "\nThat was interesting, wasn't it?")); + + assertEquals( + "Some HTML entities & special characters:\n\n```\n
<os>|<arch>[/variant]|<os>/<arch>[/variant]\n\n\nbaz")); + + // TODO + // assertEquals("Example:\n\n```\nfoo\nbar\n```", + // parser.parseConfigDescription("Example:\n\n
{@code\nfoo\nbar\n}")); + } + + @Test + public void parseJavaDocWithCodeBlock() { + assertEquals("Example:\n\n```\nfoo\nbar\n```\n\nbaz", + parser.parseConfigDescription("Example:\n\n
\nfoo\nbar\n\n\nbaz")); + + assertEquals( + "Some HTML entities & special characters:\n\n```\n
<os>|<arch>[/variant]|<os>/<arch>[/variant]\n\n\nbaz")); + + // TODO + // assertEquals("Example:\n\n```\nfoo\nbar\n```", + // parser.parseConfigDescription("Example:\n\n
{@code\nfoo\nbar\n}")); + } + @Test public void asciidoc() { String asciidoc = "== My Asciidoc\n" + @@ -308,4 +336,25 @@ public void escapeBrackets(String ch) { assertEquals(expected, actual); } + @Test + void trim() { + assertEquals("+ \nfoo", JavaDocParser.trim(new StringBuilder("+ \nfoo"))); + assertEquals("+", JavaDocParser.trim(new StringBuilder(" +"))); + assertEquals("foo", JavaDocParser.trim(new StringBuilder(" +\nfoo"))); + assertEquals("foo +", JavaDocParser.trim(new StringBuilder("foo +"))); + assertEquals("foo", JavaDocParser.trim(new StringBuilder("foo"))); + assertEquals("+", JavaDocParser.trim(new StringBuilder("+ \n"))); + assertEquals("+", JavaDocParser.trim(new StringBuilder(" +\n+ \n"))); + assertEquals("", JavaDocParser.trim(new StringBuilder(" +\n"))); + assertEquals("foo", JavaDocParser.trim(new StringBuilder(" \n\tfoo"))); + assertEquals("foo", JavaDocParser.trim(new StringBuilder("foo \n\t"))); + assertEquals("foo", JavaDocParser.trim(new StringBuilder(" \n\tfoo \n\t"))); + assertEquals("", JavaDocParser.trim(new StringBuilder(""))); + assertEquals("", JavaDocParser.trim(new StringBuilder(" \n\t"))); + assertEquals("+", JavaDocParser.trim(new StringBuilder(" +"))); + assertEquals("", JavaDocParser.trim(new StringBuilder(" +\n"))); + assertEquals("", JavaDocParser.trim(new StringBuilder(" +\n +\n"))); + assertEquals("foo +\nbar", JavaDocParser.trim(new StringBuilder(" foo +\nbar +\n"))); + } + } diff --git a/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibConfig.java b/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibConfig.java index 18f48f9aa1968..106207774b677 100644 --- a/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibConfig.java +++ b/extensions/container-image/container-image-jib/deployment/src/main/java/io/quarkus/container/image/jib/deployment/JibConfig.java @@ -147,13 +147,13 @@ public class JibConfig { * List of target platforms. Each platform is defined using the pattern: * *
- * {@literal* * for example: * *| [/variant]| / [/variant]} + * <os>|<arch>[/variant]|<os>/<arch>[/variant] *
- * {@literal linux/amd64,linux/arm64/v8} + * linux/amd64,linux/arm64/v8 ** * If not specified, OS default is linux and architecture default is {@code amd64}. diff --git a/extensions/hibernate-validator/runtime/src/main/java/io/quarkus/hibernate/validator/runtime/HibernateValidatorBuildTimeConfig.java b/extensions/hibernate-validator/runtime/src/main/java/io/quarkus/hibernate/validator/runtime/HibernateValidatorBuildTimeConfig.java index 950c2fda895a9..002b38e409414 100644 --- a/extensions/hibernate-validator/runtime/src/main/java/io/quarkus/hibernate/validator/runtime/HibernateValidatorBuildTimeConfig.java +++ b/extensions/hibernate-validator/runtime/src/main/java/io/quarkus/hibernate/validator/runtime/HibernateValidatorBuildTimeConfig.java @@ -44,11 +44,11 @@ public interface HibernateValidatorMethodBuildTimeConfig { *
* See Section 4.5.5 of the JSR 380 specification, specifically * - *
- * "In sub types (be it sub classes/interfaces or interface implementations), no parameter constraints may + *+ * This would pose a strengthening of preconditions to be fulfilled by the caller. + * */ @WithDefault("false") boolean allowOverridingParameterConstraints(); @@ -59,12 +59,12 @@ public interface HibernateValidatorMethodBuildTimeConfig { *+ * In sub types (be it sub classes/interfaces or interface implementations), no parameter constraints may * be declared on overridden or implemented methods, nor may parameters be marked for cascaded validation. - * This would pose a strengthening of preconditions to be fulfilled by the caller." - *
* See Section 4.5.5 of the JSR 380 specification, specifically * - *
- * "If a sub type overrides/implements a method originally defined in several parallel types of the hierarchy + *+ * This again is to avoid an unexpected strengthening of preconditions to be fulfilled by the caller. + * */ @WithDefault("false") boolean allowParameterConstraintsOnParallelMethods(); @@ -75,12 +75,12 @@ public interface HibernateValidatorMethodBuildTimeConfig { *+ * If a sub type overrides/implements a method originally defined in several parallel types of the hierarchy * (e.g. two interfaces not extending each other, or a class and an interface not implemented by said class), * no parameter constraints may be declared for that method at all nor parameters be marked for cascaded validation. - * This again is to avoid an unexpected strengthening of preconditions to be fulfilled by the caller." - *
* See Section 4.5.5 of the JSR 380 specification, specifically * - *
- * "One must not mark a method return value for cascaded validation more than once in a line of a class hierarchy. + *+ * overridden method of the super type or interface. + * */ @WithDefault("false") boolean allowMultipleCascadedValidationOnReturnValues(); diff --git a/extensions/security/runtime/src/main/java/io/quarkus/security/runtime/SecurityBuildTimeConfig.java b/extensions/security/runtime/src/main/java/io/quarkus/security/runtime/SecurityBuildTimeConfig.java index dccb67a7bcf13..fe0593c55c396 100644 --- a/extensions/security/runtime/src/main/java/io/quarkus/security/runtime/SecurityBuildTimeConfig.java +++ b/extensions/security/runtime/src/main/java/io/quarkus/security/runtime/SecurityBuildTimeConfig.java @@ -15,9 +15,9 @@ public class SecurityBuildTimeConfig { * E.g. if enabled, in the following bean,+ * One must not mark a method return value for cascaded validation more than once in a line of a class hierarchy. * In other words, overriding methods on sub types (be it sub classes/interfaces or interface implementations) * cannot mark the return value for cascaded validation if the return value has already been marked on the - * overridden method of the super type or interface." - *
methodB
will be denied.
*
* - * {@literal @}ApplicationScoped + * @ApplicationScoped * public class A { - * {@literal @}RolesAllowed("admin") + * @RolesAllowed("admin") * public void methodA() { * ... * }