Skip to content

Commit b957aee

Browse files
committed
Move type description to WebService.
1 parent c6f82a1 commit b957aee

File tree

4 files changed

+226
-226
lines changed

4 files changed

+226
-226
lines changed

.idea/inspectionProfiles/Project_Default.xml

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

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

Lines changed: 31 additions & 177 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import java.util.AbstractList;
2828
import java.util.AbstractMap;
2929
import java.util.AbstractSet;
30-
import java.util.Collection;
3130
import java.util.Date;
3231
import java.util.HashMap;
3332
import java.util.Iterator;
@@ -669,6 +668,37 @@ public V setValue(V value) {
669668
};
670669
}
671670

671+
/**
672+
* Returns the properties of a given type.
673+
*
674+
* @param type
675+
* The bean type.
676+
*
677+
* @return
678+
* A map containing the properties of the given type.
679+
*/
680+
public static Map<String, Type> getProperties(Class<?> type) {
681+
Method[] methods = type.getMethods();
682+
683+
TreeMap<String, Type> properties = new TreeMap<>();
684+
685+
for (int i = 0; i < methods.length; i++) {
686+
Method method = methods[i];
687+
688+
if (method.getDeclaringClass() == Object.class) {
689+
continue;
690+
}
691+
692+
String key = getKey(method);
693+
694+
if (key != null) {
695+
properties.put(key, method.getGenericReturnType());
696+
}
697+
}
698+
699+
return properties;
700+
}
701+
672702
/**
673703
* Returns the value at a given key path.
674704
*
@@ -706,180 +736,4 @@ public static <V> V valueAt(Object root, String path) {
706736

707737
return (V)value;
708738
}
709-
710-
/**
711-
* Describes a type. Types are encoded as follows:
712-
*
713-
* <ul>
714-
* <li>{@link Object}: "any"</li>
715-
* <li>{@link Void} or <code>void</code>: "void"</li>
716-
* <li>{@link Byte} or <code>byte</code>: "byte"</li>
717-
* <li>{@link Short} or <code>short</code>: "short"</li>
718-
* <li>{@link Integer} or <code>int</code>: "integer"</li>
719-
* <li>{@link Long} or <code>long</code>: "long"</li>
720-
* <li>{@link Float} or <code>float</code>: "float"</li>
721-
* <li>{@link Double} or <code>double</code>: "double"</li>
722-
* <li>Any other {@link Number}: "number"</li>
723-
* <li>{@link CharSequence}: "string"</li>
724-
* <li>{@link Enum}: "enum"</li>
725-
* <li>{@link Date}: "date"</li>
726-
* <li>{@link LocalDate}: "date-local"</li>
727-
* <li>{@link LocalTime}: "time-local"</li>
728-
* <li>{@link LocalDateTime}: "datetime-local"</li>
729-
* <li>{@link URL}: "url"</li>
730-
* <li>{@link Iterable}, {@link Collection}, or {@link List}: "[<i>element type</i>]"</li>
731-
* <li>{@link Map}: "[<i>key type</i>: <i>value type</i>]"</li>
732-
* <li>Any other type: "{property1: <i>property 1 type</i>, property2: <i>property 2 type</i>, ...}"</li>
733-
* </ul>
734-
*
735-
* @param type
736-
* The type to describe.
737-
*
738-
* @param structures
739-
* A map that will be populated with descriptions of all bean types
740-
* referenced by this type.
741-
*
742-
* @return
743-
* The type's description.
744-
*/
745-
public static String describe(Type type, Map<Class<?>, String> structures) {
746-
if (type instanceof Class<?>) {
747-
return describe((Class<?>)type, structures);
748-
} else if (type instanceof WildcardType) {
749-
WildcardType wildcardType = (WildcardType)type;
750-
751-
return describe(wildcardType.getUpperBounds()[0], structures);
752-
} else if (type instanceof ParameterizedType) {
753-
ParameterizedType parameterizedType = (ParameterizedType)type;
754-
755-
Type rawType = parameterizedType.getRawType();
756-
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
757-
758-
if (rawType == Iterable.class || rawType == Collection.class || rawType == List.class) {
759-
return "[" + describe(actualTypeArguments[0], structures) + "]";
760-
} else if (rawType == Map.class) {
761-
return "[" + describe(actualTypeArguments[0], structures) + ": " + describe(actualTypeArguments[1], structures) + "]";
762-
} else {
763-
throw new IllegalArgumentException();
764-
}
765-
} else {
766-
throw new IllegalArgumentException();
767-
}
768-
}
769-
770-
private static String describe(Class<?> type, Map<Class<?>, String> structures) {
771-
if (type == Object.class) {
772-
return "any";
773-
} else if (type == Void.TYPE || type == Void.class) {
774-
return "void";
775-
} else if (type == Byte.TYPE || type == Byte.class) {
776-
return "byte";
777-
} else if (type == Short.TYPE || type == Short.class) {
778-
return "short";
779-
} else if (type == Integer.TYPE || type == Integer.class) {
780-
return "integer";
781-
} else if (type == Long.TYPE || type == Long.class) {
782-
return "long";
783-
} else if (type == Float.TYPE || type == Float.class) {
784-
return "float";
785-
} else if (type == Double.TYPE || type == Double.class) {
786-
return "double";
787-
} else if (Number.class.isAssignableFrom(type)) {
788-
return "number";
789-
} else if (type == Boolean.TYPE || type == Boolean.class) {
790-
return "boolean";
791-
} else if (CharSequence.class.isAssignableFrom(type)) {
792-
return "string";
793-
} else if (Enum.class.isAssignableFrom(type)) {
794-
return "enum";
795-
} else if (Date.class.isAssignableFrom(type)) {
796-
return "date";
797-
} else if (type == LocalDate.class) {
798-
return "date-local";
799-
} else if (type == LocalTime.class) {
800-
return "time-local";
801-
} else if (type == LocalDateTime.class) {
802-
return "datetime-local";
803-
} else if (type == URL.class) {
804-
return "url";
805-
} else if (Iterable.class.isAssignableFrom(type)) {
806-
return describe(new ParameterizedType() {
807-
@Override
808-
public Type[] getActualTypeArguments() {
809-
return new Type[] {Object.class};
810-
}
811-
812-
@Override
813-
public Type getRawType() {
814-
return Iterable.class;
815-
}
816-
817-
@Override
818-
public Type getOwnerType() {
819-
return null;
820-
}
821-
}, structures);
822-
} else if (Map.class.isAssignableFrom(type)) {
823-
return describe(new ParameterizedType() {
824-
@Override
825-
public Type[] getActualTypeArguments() {
826-
return new Type[] {Object.class, Object.class};
827-
}
828-
829-
@Override
830-
public Type getRawType() {
831-
return Map.class;
832-
}
833-
834-
@Override
835-
public Type getOwnerType() {
836-
return null;
837-
}
838-
}, structures);
839-
} else {
840-
if (!structures.containsKey(type)) {
841-
structures.put(type, null);
842-
843-
Method[] methods = type.getMethods();
844-
845-
TreeMap<String, String> properties = new TreeMap<>();
846-
847-
for (int i = 0; i < methods.length; i++) {
848-
Method method = methods[i];
849-
850-
if (method.getDeclaringClass() == Object.class) {
851-
continue;
852-
}
853-
854-
String key = getKey(method);
855-
856-
if (key != null) {
857-
properties.put(key, describe(method.getGenericReturnType(), structures));
858-
}
859-
}
860-
861-
int j = 0;
862-
863-
StringBuilder descriptionBuilder = new StringBuilder();
864-
865-
descriptionBuilder.append("{\n");
866-
867-
for (Map.Entry<String, String> entry : properties.entrySet()) {
868-
if (j > 0) {
869-
descriptionBuilder.append(",\n");
870-
}
871-
872-
descriptionBuilder.append(" " + entry.getKey() + ": " + entry.getValue());
873-
874-
j++;
875-
}
876-
877-
descriptionBuilder.append("\n}");
878-
879-
structures.put(type, descriptionBuilder.toString());
880-
}
881-
882-
return type.getSimpleName();
883-
}
884-
}
885739
}

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

Lines changed: 61 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919

2020
import java.io.IOException;
2121
import java.io.InputStream;
22+
import java.lang.reflect.ParameterizedType;
23+
import java.lang.reflect.Type;
24+
import java.lang.reflect.WildcardType;
2225
import java.math.BigInteger;
2326
import java.net.MalformedURLException;
2427
import java.net.URL;
@@ -28,6 +31,7 @@
2831
import java.time.LocalTime;
2932
import java.util.Date;
3033
import java.util.HashMap;
34+
import java.util.List;
3135
import java.util.Map;
3236

3337
import static org.httprpc.util.Collections.entry;
@@ -144,6 +148,63 @@ public void testBeanAdapter2() throws IOException {
144148
assertFalse(result.getNestedBeanMap().get("nestedBean").getFlag());
145149
}
146150

151+
@Test
152+
public void testInterfaceKey() {
153+
TestInterface testInterface = BeanAdapter.adapt(mapOf(entry("i", 10)), TestInterface.class);
154+
155+
Map<String, ?> map = new BeanAdapter(testInterface);
156+
157+
assertEquals(10, map.get("i"));
158+
}
159+
160+
@Test
161+
public void testGetProperties() {
162+
Map<String, Type> properties = BeanAdapter.getProperties(TestBean.class);
163+
164+
assertEquals(Integer.TYPE, properties.get("i"));
165+
assertEquals(Long.TYPE, properties.get("long"));
166+
assertEquals(Double.TYPE, properties.get("double"));
167+
assertEquals(String.class, properties.get("string"));
168+
assertEquals(BigInteger.class, properties.get("bigInteger"));
169+
assertEquals(DayOfWeek.class, properties.get("dayOfWeek"));
170+
assertEquals(Date.class, properties.get("date"));
171+
assertEquals(LocalDate.class, properties.get("localDate"));
172+
assertEquals(LocalTime.class, properties.get("localTime"));
173+
assertEquals(LocalDateTime.class, properties.get("localDateTime"));
174+
assertEquals(URL.class, properties.get("URL"));
175+
assertEquals(TestBean.NestedBean.class, properties.get("nestedBean"));
176+
177+
assertTrue(properties.get("list") instanceof ParameterizedType);
178+
179+
Type[] listTypeArguments = ((ParameterizedType)properties.get("list")).getActualTypeArguments();
180+
181+
assertEquals(1, listTypeArguments.length);
182+
assertTrue(listTypeArguments[0] instanceof WildcardType);
183+
184+
assertEquals(TestBean.TestArrayList.class, properties.get("testArrayList"));
185+
186+
Type[] nestedBeanListTypeArguments = ((ParameterizedType)properties.get("nestedBeanList")).getActualTypeArguments();
187+
188+
assertEquals(1, nestedBeanListTypeArguments.length);
189+
assertEquals(TestBean.NestedBean.class, nestedBeanListTypeArguments[0]);
190+
191+
assertTrue(properties.get("map") instanceof ParameterizedType);
192+
193+
Type[] mapTypeArguments = ((ParameterizedType)properties.get("map")).getActualTypeArguments();
194+
195+
assertEquals(2, mapTypeArguments.length);
196+
assertEquals(String.class, mapTypeArguments[0]);
197+
assertTrue(mapTypeArguments[1] instanceof WildcardType);
198+
199+
assertEquals(TestBean.TestHashMap.class, properties.get("testHashMap"));
200+
201+
Type[] nestedBeanMapTypeArguments = ((ParameterizedType)properties.get("nestedBeanMap")).getActualTypeArguments();
202+
203+
assertEquals(2, nestedBeanMapTypeArguments.length);
204+
assertEquals(String.class, nestedBeanMapTypeArguments[0]);
205+
assertEquals(TestBean.NestedBean.class, nestedBeanMapTypeArguments[1]);
206+
}
207+
147208
@Test
148209
public void testValueAt() {
149210
Map<String, ?> map = mapOf(
@@ -156,51 +217,4 @@ public void testValueAt() {
156217

157218
assertEquals(Integer.valueOf(123), BeanAdapter.valueAt(map, "a.b.c"));
158219
}
159-
160-
@Test
161-
public void testDescribe() {
162-
HashMap<Class<?>, String> structures = new HashMap<>();
163-
164-
BeanAdapter.describe(TestBean.class, structures);
165-
166-
assertEquals(
167-
"{\n" +
168-
" URL: url,\n" +
169-
" bigInteger: number,\n" +
170-
" date: date,\n" +
171-
" dayOfWeek: enum,\n" +
172-
" double: double,\n" +
173-
" i: integer,\n" +
174-
" list: [any],\n" +
175-
" localDate: date-local,\n" +
176-
" localDateTime: datetime-local,\n" +
177-
" localTime: time-local,\n" +
178-
" long: long,\n" +
179-
" map: [string: any],\n" +
180-
" nestedBean: NestedBean,\n" +
181-
" nestedBeanList: [NestedBean],\n" +
182-
" nestedBeanMap: [string: NestedBean],\n" +
183-
" string: string,\n" +
184-
" testArrayList: [any],\n" +
185-
" testHashMap: [any: any]\n" +
186-
"}",
187-
structures.get(TestBean.class)
188-
);
189-
190-
assertEquals(
191-
"{\n" +
192-
" flag: boolean\n" +
193-
"}",
194-
structures.get(TestBean.NestedBean.class)
195-
);
196-
}
197-
198-
@Test
199-
public void testInterfaceKey() {
200-
TestInterface testInterface = BeanAdapter.adapt(mapOf(entry("i", 10)), TestInterface.class);
201-
202-
Map<String, ?> map = new BeanAdapter(testInterface);
203-
204-
assertEquals(10, map.get("i"));
205-
}
206220
}

0 commit comments

Comments
 (0)