Skip to content

Commit 4fe3e74

Browse files
laurentschoelenslukasj
authored andcommitted
[#1826] XJC should preserve some XML entities in generated JavaDoc
1 parent f4ece6f commit 4fe3e74

File tree

14 files changed

+156
-25
lines changed

14 files changed

+156
-25
lines changed

jaxb-ri/codemodel/codemodel/src/main/java/com/sun/codemodel/JCommentPart.java

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 1997, 2021 Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2025 Contributors to the Eclipse Foundation. All rights reserved.
34
*
45
* This program and the accompanying materials are made available under the
56
* terms of the Eclipse Distribution License v. 1.0, which is available at
@@ -10,9 +11,11 @@
1011

1112
package com.sun.codemodel;
1213

14+
import java.util.AbstractMap;
1315
import java.util.ArrayList;
1416
import java.util.Collection;
1517
import java.util.Iterator;
18+
import java.util.List;
1619

1720
/**
1821
* A part is a part of a javadoc comment, and it is a list of values.
@@ -31,6 +34,13 @@
3134
public class JCommentPart extends ArrayList<Object> {
3235

3336
private static final long serialVersionUID = 1L;
37+
private static final List<AbstractMap.SimpleImmutableEntry<String, String>> ESCAPED_XML_JAVADOC = new ArrayList<>();
38+
static {
39+
ESCAPED_XML_JAVADOC.add(new AbstractMap.SimpleImmutableEntry<>("&", "&amp;"));
40+
ESCAPED_XML_JAVADOC.add(new AbstractMap.SimpleImmutableEntry<>("<", "&lt;"));
41+
ESCAPED_XML_JAVADOC.add(new AbstractMap.SimpleImmutableEntry<>(">", "&gt;"));
42+
ESCAPED_XML_JAVADOC.add(new AbstractMap.SimpleImmutableEntry<>("@", "&#064;"));
43+
}
3444

3545
protected JCommentPart() {
3646
}
@@ -46,7 +56,18 @@ public JCommentPart append(Object o) {
4656
return this;
4757
}
4858

49-
@Override
59+
/**
60+
* Appends a new value with escaped XML.
61+
*
62+
* If the value is {@link JType} it will be printed as a @link tag.
63+
* Otherwise it will be converted to String via {@link Object#toString()}.
64+
*/
65+
public JCommentPart appendXML(String s) {
66+
add(escapeXML(s));
67+
return this;
68+
}
69+
70+
@Override
5071
public boolean add(Object o) {
5172
flattenAppend(o);
5273
return true;
@@ -112,6 +133,29 @@ protected void format( JFormatter f, String indent ) {
112133
f.nl();
113134
}
114135

136+
/**
137+
* Escapes the XML tags for Javadoc compatibility
138+
*/
139+
private String escapeXML(String s) {
140+
if (s == null) {
141+
return s;
142+
}
143+
for (AbstractMap.SimpleImmutableEntry<String, String> entry : ESCAPED_XML_JAVADOC) {
144+
int entryKeyLength = entry.getKey().length();
145+
int entryValueLength = entry.getValue().length();
146+
int idx = -1;
147+
while (true) {
148+
idx = s.indexOf(entry.getKey(), idx);
149+
if (idx < 0) {
150+
break;
151+
}
152+
s = s.substring(0, idx) + entry.getValue() + s.substring(idx + entryKeyLength);
153+
idx += entryValueLength;
154+
}
155+
}
156+
return s;
157+
}
158+
115159
/**
116160
* Escapes the appearance of the comment terminator.
117161
*/

jaxb-ri/codemodel/codemodel/src/main/java/com/sun/codemodel/JDocComment.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 1997, 2022 Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2025 Contributors to the Eclipse Foundation. All rights reserved.
34
*
45
* This program and the accompanying materials are made available under the
56
* terms of the Eclipse Distribution License v. 1.0, which is available at
@@ -54,12 +55,18 @@ public JDocComment(JCodeModel owner) {
5455
this.owner = owner;
5556
}
5657

57-
@Override
58+
@Override
5859
public JDocComment append(Object o) {
5960
add(o);
6061
return this;
6162
}
6263

64+
@Override
65+
public JDocComment appendXML(String s) {
66+
super.appendXML(s);
67+
return this;
68+
}
69+
6370
/**
6471
* Append a text to a @param tag to the javadoc
6572
*/

jaxb-ri/codemodel/codemodel/src/test/java/com/sun/codemodel/tests/JCommentTest.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2025 Contributors to the Eclipse Foundation. All rights reserved.
34
*
45
* This program and the accompanying materials are made available under the
56
* terms of the Eclipse Distribution License v. 1.0, which is available at
@@ -44,4 +45,28 @@ public void testJavadoc() throws Throwable {
4445
assertTrue(generatedClass.contains("</p>"));
4546
assertFalse(generatedClass.contains("&"));
4647
}
48+
49+
/**
50+
* This should produce the following javadoc :<br><br>
51+
* Age &lt;&gt; 18 &amp; age &lt;&gt; 21 &#064;home
52+
*/
53+
public void testJavadocXML() throws Throwable {
54+
JCodeModel model = new JCodeModel();
55+
String className = "gh1826.JavadocTest";
56+
JDefinedClass cls = model._class(className, ClassType.CLASS);
57+
JDocComment comment = cls.javadoc();
58+
comment.appendXML("Age <> 18 & age <> 21 @home");
59+
60+
ByteArrayOutputStream os = new ByteArrayOutputStream();
61+
OutputStreamCodeWriter fileCodeWriter = new OutputStreamCodeWriter(os, "UTF-8");
62+
model.build(fileCodeWriter);
63+
64+
String generatedClass = os.toString(StandardCharsets.UTF_8);
65+
System.out.println(generatedClass);
66+
assertFalse(generatedClass.contains("<"));
67+
assertFalse(generatedClass.contains(">"));
68+
assertFalse(generatedClass.contains("@"));
69+
assertTrue(generatedClass.contains("&amp;"));
70+
assertTrue(generatedClass.contains("&#064;"));
71+
}
4772
}

jaxb-ri/xjc/src/main/java/com/sun/tools/xjc/generator/bean/BeanGenerator.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2025 Contributors to the Eclipse Foundation. All rights reserved.
34
*
45
* This program and the accompanying materials are made available under the
56
* terms of the Eclipse Distribution License v. 1.0, which is available at
@@ -556,7 +557,7 @@ private void generateClassBody(ClassOutlineImpl cc) {
556557
}
557558

558559
// generate some class level javadoc
559-
cc.ref.javadoc().append(target.javadoc);
560+
cc.ref.javadoc().appendXML(target.javadoc);
560561

561562
cc._package().objectFactoryGenerator().populate(cc);
562563
}
@@ -615,7 +616,7 @@ private EnumOutline generateEnumDef(CEnumLeafInfo e) {
615616

616617
type = getClassFactory().createClass(
617618
getContainer(e.parent, EXPOSED), e.shortName, e.getLocator(), ClassType.ENUM);
618-
type.javadoc().append(e.javadoc);
619+
type.javadoc().appendXML(e.javadoc);
619620

620621
return new EnumOutline(e, type) {
621622

@@ -682,7 +683,7 @@ private void generateEnumBody(EnumOutline eo) {
682683

683684
// set javadoc
684685
if (mem.javadoc != null) {
685-
constRef.javadoc().append(mem.javadoc);
686+
constRef.javadoc().appendXML(mem.javadoc);
686687
}
687688

688689
eo.constants.add(new EnumConstantOutline(mem, constRef) {

jaxb-ri/xjc/src/main/java/com/sun/tools/xjc/generator/bean/field/AbstractFieldWithVar.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2025 Contributors to the Eclipse Foundation. All rights reserved.
34
*
45
* This program and the accompanying materials are made available under the
56
* terms of the Eclipse Distribution License v. 1.0, which is available at
@@ -47,7 +48,7 @@ protected final void createField() {
4748
getFieldType(), prop.getName(false) );
4849

4950
if (prop.javadoc != null && prop.javadoc.length() > 0) {
50-
field.javadoc().add(prop.javadoc);
51+
field.javadoc().appendXML(prop.javadoc);
5152
}
5253

5354
annotate(field);

jaxb-ri/xjc/src/main/java/com/sun/tools/xjc/generator/bean/field/AbstractListField.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2025 Contributors to the Eclipse Foundation. All rights reserved.
34
*
45
* This program and the accompanying materials are made available under the
56
* terms of the Eclipse Distribution License v. 1.0, which is available at
@@ -99,7 +100,7 @@ protected final void generate() {
99100
field.init(newCoreList());
100101

101102
if (prop.javadoc != null && prop.javadoc.length() > 0) {
102-
field.javadoc().add(prop.javadoc);
103+
field.javadoc().appendXML(prop.javadoc);
103104
}
104105

105106
annotate(field);

jaxb-ri/xjc/src/main/java/com/sun/tools/xjc/generator/bean/field/ArrayField.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2025 Contributors to the Eclipse Foundation. All rights reserved.
34
*
45
* This program and the accompanying materials are made available under the
56
* terms of the Eclipse Distribution License v. 1.0, which is available at
@@ -102,7 +103,7 @@ public void generateAccessors() {
102103
// }
103104
$getAll = writer.declareMethod( exposedType.array(),"get"+prop.getName(true));
104105
if (prop.javadoc != null && prop.javadoc.length() > 0) {
105-
writer.javadoc().append(prop.javadoc).append("\n\n");
106+
writer.javadoc().appendXML(prop.javadoc).append("\n\n");
106107
}
107108
body = $getAll.body();
108109

@@ -129,7 +130,7 @@ public void generateAccessors() {
129130
$get.body()._if(acc.ref(true).eq(JExpr._null()))._then()
130131
._throw(JExpr._new(codeModel.ref(IndexOutOfBoundsException.class)));
131132

132-
writer.javadoc().append(prop.javadoc);
133+
writer.javadoc().appendXML(prop.javadoc);
133134
$get.body()._return(acc.ref(true).component($idx));
134135

135136
writer.javadoc().addReturn().append("one of\n").append(returnTypes);
@@ -156,7 +157,7 @@ public void generateAccessors() {
156157
codeModel.VOID,
157158
"set"+prop.getName(true));
158159

159-
writer.javadoc().append(prop.javadoc);
160+
writer.javadoc().appendXML(prop.javadoc);
160161
$value = writer.addParameter(exposedType.array(),"values");
161162

162163
$setAll.body()._if( $value.eq(JExpr._null()) )._then()
@@ -189,7 +190,7 @@ public void generateAccessors() {
189190
$idx = writer.addParameter( codeModel.INT, "idx" );
190191
$value = writer.addParameter( exposedType, "value" );
191192

192-
writer.javadoc().append(prop.javadoc);
193+
writer.javadoc().appendXML(prop.javadoc);
193194

194195
body = $set.body();
195196
body._return( JExpr.assign(acc.ref(true).component($idx),

jaxb-ri/xjc/src/main/java/com/sun/tools/xjc/generator/bean/field/ConstField.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 1997, 2024 Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2025 Contributors to the Eclipse Foundation. All rights reserved.
34
*
45
* This program and the accompanying materials are made available under the
56
* terms of the Eclipse Distribution License v. 1.0, which is available at
@@ -57,7 +58,7 @@ final class ConstField extends AbstractField {
5758

5859
// Do not append empty javadoc.
5960
if ( (prop.javadoc != null) && (prop.javadoc.length() > 0) )
60-
$ref.javadoc().append(prop.javadoc);
61+
$ref.javadoc().appendXML(prop.javadoc);
6162

6263
annotate($ref);
6364
}

jaxb-ri/xjc/src/main/java/com/sun/tools/xjc/generator/bean/field/ContentListField.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2025 Contributors to the Eclipse Foundation. All rights reserved.
34
*
45
* This program and the accompanying materials are made available under the
56
* terms of the Eclipse Distribution License v. 1.0, which is available at
@@ -101,7 +102,7 @@ public void generateAccessors() {
101102
// }
102103
$get = writer.declareMethod(listT,"get"+prop.getName(true));
103104
if (prop.javadoc != null && prop.javadoc.length() > 0) {
104-
writer.javadoc().append(prop.javadoc).append("\n\n");
105+
writer.javadoc().appendXML(prop.javadoc).append("\n\n");
105106
}
106107
JBlock block = $get.body();
107108
fixNullRef(block); // avoid using an internal getter

jaxb-ri/xjc/src/main/java/com/sun/tools/xjc/generator/bean/field/NoExtendedContentField.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2025 Contributors to the Eclipse Foundation. All rights reserved.
34
*
45
* This program and the accompanying materials are made available under the
56
* terms of the Eclipse Distribution License v. 1.0, which is available at
@@ -104,7 +105,7 @@ public void generateAccessors() {
104105
// }
105106
$get = writer.declareMethod(listT,"get"+prop.getName(true));
106107
if (prop.javadoc != null && prop.javadoc.length() > 0) {
107-
writer.javadoc().append(prop.javadoc).append("\n\n");
108+
writer.javadoc().appendXML(prop.javadoc).append("\n\n");
108109
}
109110
JBlock block = $get.body();
110111
fixNullRef(block); // avoid using an internal getter

0 commit comments

Comments
 (0)