Skip to content

Commit 2d9cd84

Browse files
committed
Add support for bean property descriptions.
1 parent 63f2a19 commit 2d9cd84

File tree

11 files changed

+136
-112
lines changed

11 files changed

+136
-112
lines changed

.idea/inspectionProfiles/Project_Default.xml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,8 @@ Methods are grouped by resource path. Parameter and return types are encoded as
258258
* `java.net.URL`: "file" for parameters, "url" for return values
259259
* `java.lang.Iterable`, `java.util.Collection`, or `java.util.List`: "[<em>element type</em>]"
260260
* `java.util.Map`: "[<em>key type</em>: <em>value type</em>]"
261-
* Any other type: "{property1: <em>property1 type</em>, property2: <em>property2 type</em>, ...}"
261+
262+
Any other type is considered a Java bean and is described by its simple class name.
262263

263264
Implementations can provide additional information about service types and operations using the `Description` annotation. For example:
264265

@@ -280,6 +281,24 @@ public class MathService extends WebService {
280281
}
281282
```
282283

284+
The `Description` annotation can also be applied to bean properties:
285+
286+
```java
287+
public static class Item {
288+
...
289+
290+
@Description("The item's description.")
291+
public String getDescription() {
292+
return description;
293+
}
294+
295+
@Description("The item's price.")
296+
public double getPrice() {
297+
return price;
298+
}
299+
}
300+
```
301+
283302
If a method is tagged with the `Deprecated` annotation, it will be identified as such in the output.
284303

285304
## WebServiceProxy

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
subprojects {
1616
group = 'org.httprpc'
17-
version = '7.5.6'
17+
version = '7.6'
1818

1919
apply plugin: 'java-library'
2020
apply plugin: 'maven-publish'

httprpc-client/src/main/java/org/httprpc/beans/BeanAdapter.java

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -236,23 +236,7 @@ private BeanAdapter(Object bean, HashMap<Class<?>, TreeMap<String, Method>> acce
236236
accessors = accessorCache.get(type);
237237

238238
if (accessors == null) {
239-
accessors = new TreeMap<>();
240-
241-
Method[] methods = type.getMethods();
242-
243-
for (int i = 0; i < methods.length; i++) {
244-
Method method = methods[i];
245-
246-
if (method.getDeclaringClass() == Object.class) {
247-
continue;
248-
}
249-
250-
String key = getKey(method);
251-
252-
if (key != null) {
253-
accessors.put(key, method);
254-
}
255-
}
239+
accessors = getAccessors(type);
256240

257241
accessorCache.put(type, accessors);
258242
}
@@ -718,18 +702,18 @@ public V setValue(V value) {
718702
}
719703

720704
/**
721-
* Returns the properties of a given type.
705+
* Returns the accessors for a given type.
722706
*
723707
* @param type
724708
* The bean type.
725709
*
726710
* @return
727-
* A map containing the properties of the given type.
711+
* The accessors defined by the given type.
728712
*/
729-
public static Map<String, Type> getProperties(Class<?> type) {
730-
Method[] methods = type.getMethods();
713+
public static TreeMap<String, Method> getAccessors(Class<?> type) {
714+
TreeMap<String, Method> accessors = new TreeMap<>();
731715

732-
TreeMap<String, Type> properties = new TreeMap<>();
716+
Method[] methods = type.getMethods();
733717

734718
for (int i = 0; i < methods.length; i++) {
735719
Method method = methods[i];
@@ -741,10 +725,10 @@ public static Map<String, Type> getProperties(Class<?> type) {
741725
String key = getKey(method);
742726

743727
if (key != null) {
744-
properties.put(key, method.getGenericReturnType());
728+
accessors.put(key, method);
745729
}
746730
}
747731

748-
return properties;
732+
return accessors;
749733
}
750734
}

httprpc-client/src/test/java/org/httprpc/beans/BeanAdapterTest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import java.util.Date;
3434
import java.util.HashMap;
3535
import java.util.Map;
36+
import java.util.stream.Collectors;
3637

3738
import static org.httprpc.util.Collections.entry;
3839
import static org.httprpc.util.Collections.listOf;
@@ -191,7 +192,8 @@ public void testInstant() {
191192

192193
@Test
193194
public void testGetProperties() {
194-
Map<String, Type> properties = BeanAdapter.getProperties(TestBean.class);
195+
Map<String, Type> properties = BeanAdapter.getAccessors(TestBean.class).entrySet().stream()
196+
.collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getGenericReturnType()));
195197

196198
assertEquals(Integer.TYPE, properties.get("i"));
197199
assertEquals(Long.TYPE, properties.get("long"));

httprpc-server/src/main/java/org/httprpc/WebService.java

Lines changed: 39 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -614,29 +614,52 @@ private void describeService(HttpServletRequest request, HttpServletResponse res
614614

615615
xmlStreamWriter.writeStartElement("body");
616616

617-
TreeMap<Class<?>, String> structures = new TreeMap<>(Comparator.comparing(Class::getSimpleName));
617+
TreeMap<Class<?>, TreeMap<String, Method>> structures = new TreeMap<>(Comparator.comparing(Class::getSimpleName));
618618

619-
Description description = getClass().getAnnotation(Description.class);
619+
Description serviceDescription = getClass().getAnnotation(Description.class);
620620

621-
if (description != null) {
621+
if (serviceDescription != null) {
622622
xmlStreamWriter.writeStartElement("p");
623-
xmlStreamWriter.writeCharacters(description.value());
623+
xmlStreamWriter.writeCharacters(serviceDescription.value());
624624
xmlStreamWriter.writeEndElement();
625625
}
626626

627627
describeResource(request.getServletPath(), root, structures, xmlStreamWriter);
628628

629-
for (Map.Entry<Class<?>, String> entry : structures.entrySet()) {
630-
Class<?> type = entry.getKey();
629+
for (Map.Entry<Class<?>, TreeMap<String, Method>> typeEntry : structures.entrySet()) {
630+
Class<?> type = typeEntry.getKey();
631631

632632
String name = type.getSimpleName();
633633

634634
xmlStreamWriter.writeStartElement("h3");
635635
xmlStreamWriter.writeCharacters(name);
636636
xmlStreamWriter.writeEndElement();
637637

638-
xmlStreamWriter.writeStartElement("pre");
639-
xmlStreamWriter.writeCharacters(entry.getValue());
638+
xmlStreamWriter.writeStartElement("ul");
639+
640+
for (Map.Entry<String, Method> propertyEntry : typeEntry.getValue().entrySet()) {
641+
Method method = propertyEntry.getValue();
642+
643+
xmlStreamWriter.writeStartElement("li");
644+
645+
xmlStreamWriter.writeStartElement("code");
646+
647+
xmlStreamWriter.writeCharacters(propertyEntry.getKey());
648+
xmlStreamWriter.writeCharacters(": ");
649+
xmlStreamWriter.writeCharacters(describe(method.getGenericReturnType(), null));
650+
651+
xmlStreamWriter.writeEndElement();
652+
653+
Description propertyDescription = method.getAnnotation(Description.class);
654+
655+
if (propertyDescription != null) {
656+
xmlStreamWriter.writeCharacters(" - ");
657+
xmlStreamWriter.writeCharacters(propertyDescription.value());
658+
}
659+
660+
xmlStreamWriter.writeEndElement();
661+
}
662+
640663
xmlStreamWriter.writeEndElement();
641664
}
642665

@@ -649,7 +672,7 @@ private void describeService(HttpServletRequest request, HttpServletResponse res
649672
}
650673
}
651674

652-
private void describeResource(String path, Resource resource, TreeMap<Class<?>, String> structures,
675+
private void describeResource(String path, Resource resource, TreeMap<Class<?>, TreeMap<String, Method>> structures,
653676
XMLStreamWriter xmlStreamWriter) throws XMLStreamException {
654677
if (!resource.handlerMap.isEmpty()) {
655678
xmlStreamWriter.writeStartElement("h2");
@@ -735,7 +758,7 @@ private void describeResource(String path, Resource resource, TreeMap<Class<?>,
735758
}
736759
}
737760

738-
private static String describe(Type type, Map<Class<?>, String> structures) {
761+
private static String describe(Type type, Map<Class<?>, TreeMap<String, Method>> structures) {
739762
if (type instanceof Class<?>) {
740763
return describe((Class<?>)type, structures);
741764
} else if (type instanceof WildcardType) {
@@ -760,7 +783,7 @@ private static String describe(Type type, Map<Class<?>, String> structures) {
760783
}
761784
}
762785

763-
private static String describe(Class<?> type, Map<Class<?>, String> structures) {
786+
private static String describe(Class<?> type, Map<Class<?>, TreeMap<String, Method>> structures) {
764787
if (type == Object.class) {
765788
return "any";
766789
} else if (type == Void.TYPE || type == Void.class) {
@@ -832,30 +855,14 @@ public Type getOwnerType() {
832855
}
833856
}, structures);
834857
} else {
835-
if (!structures.containsKey(type)) {
836-
structures.put(type, null);
837-
838-
Map<String, Type> properties = BeanAdapter.getProperties(type);
839-
840-
StringBuilder structureBuilder = new StringBuilder();
841-
842-
structureBuilder.append("{\n");
858+
if (structures != null && !structures.containsKey(type)) {
859+
TreeMap<String, Method> accessors = BeanAdapter.getAccessors(type);
843860

844-
int i = 0;
861+
structures.put(type, accessors);
845862

846-
for (Map.Entry<String, Type> entry : properties.entrySet()) {
847-
if (i > 0) {
848-
structureBuilder.append(",\n");
849-
}
850-
851-
structureBuilder.append(" " + entry.getKey() + ": " + describe(entry.getValue(), structures));
852-
853-
i++;
863+
for (Map.Entry<String, Method> entry : accessors.entrySet()) {
864+
describe(entry.getValue().getGenericReturnType(), structures);
854865
}
855-
856-
structureBuilder.append("\n}");
857-
858-
structures.put(type, structureBuilder.toString());
859866
}
860867

861868
return type.getSimpleName();

httprpc-test/src/main/java/org/httprpc/test/CatalogService.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ private Item(String description, double price) {
3737
this.price = price;
3838
}
3939

40+
@Description("The item's description.")
4041
public String getDescription() {
4142
return description;
4243
}
@@ -45,6 +46,7 @@ private void setDescription(String description) {
4546
this.description = description;
4647
}
4748

49+
@Description("The item's price.")
4850
public double getPrice() {
4951
return price;
5052
}

httprpc-test/src/main/java/org/httprpc/test/TestService.java

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.httprpc.RequestMethod;
1818
import org.httprpc.ResourcePath;
1919
import org.httprpc.WebService;
20+
import org.httprpc.beans.BeanAdapter;
2021

2122
import javax.servlet.annotation.MultipartConfig;
2223
import javax.servlet.annotation.WebServlet;
@@ -47,6 +48,24 @@
4748
@WebServlet(urlPatterns={"/test/*"}, loadOnStartup=1)
4849
@MultipartConfig
4950
public class TestService extends WebService {
51+
public interface Response {
52+
interface AttachmentInfo {
53+
int getBytes();
54+
int getChecksum();
55+
}
56+
57+
String getString();
58+
List<String> getStrings();
59+
int getNumber();
60+
boolean getFlag();
61+
Date getDate();
62+
Instant getInstant();
63+
LocalDate getLocalDate();
64+
LocalTime getLocalTime();
65+
LocalDateTime getLocalDateTime();
66+
List<AttachmentInfo> getAttachmentInfo();
67+
}
68+
5069
@RequestMethod("GET")
5170
public Map<String, ?> testGet(String string, List<String> strings, int number, boolean flag,
5271
Date date, Instant instant, LocalDate localDate, LocalTime localTime, LocalDateTime localDateTime) {
@@ -127,7 +146,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t
127146
}
128147

129148
@RequestMethod("POST")
130-
public Map<String, ?> testPost(String string, List<String> strings, int number, boolean flag,
149+
public Response testPost(String string, List<String> strings, int number, boolean flag,
131150
Date date, Instant instant, LocalDate localDate, LocalTime localTime, LocalDateTime localDateTime,
132151
List<URL> attachments) throws IOException {
133152
List<Map<String, ?>> attachmentInfo = new LinkedList<>();
@@ -150,7 +169,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t
150169
));
151170
}
152171

153-
return mapOf(
172+
return BeanAdapter.adapt(mapOf(
154173
entry("string", string),
155174
entry("strings", strings),
156175
entry("number", number),
@@ -161,7 +180,7 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t
161180
entry("localTime", localTime),
162181
entry("localDateTime", localDateTime),
163182
entry("attachmentInfo", attachmentInfo)
164-
);
183+
), Response.class);
165184
}
166185

167186
@RequestMethod("POST")

httprpc-test/src/main/java/org/httprpc/test/TreeNode.java

Lines changed: 0 additions & 42 deletions
This file was deleted.

0 commit comments

Comments
 (0)