|
20 | 20 |
|
21 | 21 | import static com.google.common.base.Preconditions.checkArgument; |
22 | 22 | import static java.util.Objects.requireNonNull; |
| 23 | +import static javaslang.API.Case; |
| 24 | +import static javaslang.API.Match; |
| 25 | +import static javaslang.Predicates.instanceOf; |
23 | 26 |
|
| 27 | +import java.lang.reflect.Array; |
24 | 28 | import java.lang.reflect.Method; |
25 | 29 | import java.util.ArrayList; |
26 | 30 | import java.util.Arrays; |
|
42 | 46 | import com.google.common.collect.ImmutableList; |
43 | 47 | import com.google.common.collect.ImmutableMap; |
44 | 48 | import com.google.common.collect.Lists; |
| 49 | +import com.google.common.primitives.Primitives; |
45 | 50 | import com.google.inject.Key; |
46 | 51 | import com.google.inject.TypeLiteral; |
47 | 52 |
|
@@ -218,13 +223,14 @@ public interface Route { |
218 | 223 | */ |
219 | 224 | interface Attributes<T extends Attributes<T>> { |
220 | 225 | /** |
221 | | - * Set route attribute. |
| 226 | + * Set route attribute. Only primitives, string, class, enum or array of previous types are |
| 227 | + * allowed as attributes values. |
222 | 228 | * |
223 | 229 | * @param name Attribute's name. |
224 | 230 | * @param value Attribute's value. |
225 | 231 | * @return This instance. |
226 | 232 | */ |
227 | | - T attr(String name, String value); |
| 233 | + T attr(String name, Object value); |
228 | 234 |
|
229 | 235 | /** |
230 | 236 | * Tell jooby what renderer should use to render the output. |
@@ -653,7 +659,7 @@ public Group produces(final List<MediaType> types) { |
653 | 659 | } |
654 | 660 |
|
655 | 661 | @Override |
656 | | - public Group attr(final String name, final String value) { |
| 662 | + public Group attr(final String name, final Object value) { |
657 | 663 | for (Definition definition : routes) { |
658 | 664 | definition.attr(name, value); |
659 | 665 | } |
@@ -742,7 +748,7 @@ public Collection produces(final List<MediaType> types) { |
742 | 748 | } |
743 | 749 |
|
744 | 750 | @Override |
745 | | - public Collection attr(final String name, final String value) { |
| 751 | + public Collection attr(final String name, final Object value) { |
746 | 752 | for (Definition definition : routes) { |
747 | 753 | definition.attr(name, value); |
748 | 754 | } |
@@ -858,7 +864,7 @@ class Definition implements Attributes<Definition> { |
858 | 864 |
|
859 | 865 | private List<RoutePattern> excludes = Collections.emptyList(); |
860 | 866 |
|
861 | | - private Map<String, String> attributes = new HashMap<>(); |
| 867 | + private Map<String, Object> attributes = new HashMap<>(); |
862 | 868 |
|
863 | 869 | /** |
864 | 870 | * Creates a new route definition. |
@@ -980,35 +986,41 @@ public String reverse(final Object... values) { |
980 | 986 | return cpattern.reverse(values); |
981 | 987 | } |
982 | 988 |
|
983 | | - /** |
984 | | - * Set route attribute. |
985 | | - * |
986 | | - * @param name Attribute's name. |
987 | | - * @param value Attribute's value. |
988 | | - * @return This instance. |
989 | | - */ |
990 | 989 | @Override |
991 | | - public Definition attr(final String name, final String value) { |
992 | | - requireNonNull(name, "A name is required."); |
993 | | - requireNonNull(value, "A value is required."); |
| 990 | + public Definition attr(final String name, final Object value) { |
| 991 | + requireNonNull(name, "Attribute name is required."); |
| 992 | + requireNonNull(value, "Attribute value is required."); |
| 993 | + |
| 994 | + validate(value); |
994 | 995 | attributes.put(name, value); |
995 | 996 | return this; |
996 | 997 | } |
997 | 998 |
|
| 999 | + private boolean validate(final Object value) { |
| 1000 | + return Match(value).option( |
| 1001 | + Case(v -> Primitives.isWrapperType(Primitives.wrap(v.getClass())), true), |
| 1002 | + Case(instanceOf(String.class), true), |
| 1003 | + Case(instanceOf(Enum.class), true), |
| 1004 | + Case(instanceOf(Class.class), true), |
| 1005 | + Case(c -> c.getClass().isArray(), v -> validate(Array.get(v, 0)))) |
| 1006 | + .getOrElseThrow(() -> new IllegalArgumentException("Unsupported attribute: " + value)); |
| 1007 | + } |
| 1008 | + |
998 | 1009 | /** |
999 | 1010 | * Get an attribute by name. |
1000 | 1011 | * |
1001 | 1012 | * @param name Attribute's name. |
1002 | | - * @return Attribute's value. |
| 1013 | + * @return Attribute's value or <code>null</code>. |
1003 | 1014 | */ |
1004 | | - public Optional<String> attr(final String name) { |
1005 | | - return Optional.ofNullable(attributes.get(name)); |
| 1015 | + @SuppressWarnings("unchecked") |
| 1016 | + public <T> T attr(final String name) { |
| 1017 | + return (T) attributes.get(name); |
1006 | 1018 | } |
1007 | 1019 |
|
1008 | 1020 | /** |
1009 | 1021 | * @return A read only view of attributes. |
1010 | 1022 | */ |
1011 | | - public Map<String, String> attributes() { |
| 1023 | + public Map<String, Object> attributes() { |
1012 | 1024 | return ImmutableMap.copyOf(attributes); |
1013 | 1025 | } |
1014 | 1026 |
|
@@ -1281,12 +1293,12 @@ public List<MediaType> produces() { |
1281 | 1293 | } |
1282 | 1294 |
|
1283 | 1295 | @Override |
1284 | | - public Map<String, String> attributes() { |
| 1296 | + public Map<String, Object> attributes() { |
1285 | 1297 | return route.attributes(); |
1286 | 1298 | } |
1287 | 1299 |
|
1288 | 1300 | @Override |
1289 | | - public String attr(final String name) { |
| 1301 | + public <T> T attr(final String name) { |
1290 | 1302 | return route.attr(name); |
1291 | 1303 | } |
1292 | 1304 |
|
@@ -1918,16 +1930,17 @@ default boolean apply(final String prefix) { |
1918 | 1930 | /** |
1919 | 1931 | * @return All the available attributes in the execution chain. |
1920 | 1932 | */ |
1921 | | - Map<String, String> attributes(); |
| 1933 | + Map<String, Object> attributes(); |
1922 | 1934 |
|
1923 | 1935 | /** |
1924 | 1936 | * Attribute by name. |
1925 | 1937 | * |
1926 | 1938 | * @param name Attribute's name. |
1927 | 1939 | * @return Attribute value. |
1928 | 1940 | */ |
1929 | | - default String attr(final String name) { |
1930 | | - return attributes().get(name); |
| 1941 | + @SuppressWarnings("unchecked") |
| 1942 | + default <T> T attr(final String name) { |
| 1943 | + return (T) attributes().get(name); |
1931 | 1944 | } |
1932 | 1945 |
|
1933 | 1946 | /** |
|
0 commit comments