diff --git a/lib/src/main/java/com/auth0/jwt/JWTCreator.java b/lib/src/main/java/com/auth0/jwt/JWTCreator.java
index bfcb9147..f079a425 100644
--- a/lib/src/main/java/com/auth0/jwt/JWTCreator.java
+++ b/lib/src/main/java/com/auth0/jwt/JWTCreator.java
@@ -351,10 +351,10 @@ public Builder withClaim(String name, Instant value) throws IllegalArgumentExcep
/**
* Add a custom Map Claim with the given items.
*
- * Accepted nested types are {@linkplain Map} and {@linkplain List} with basic types
+ * Accepted nested types are {@linkplain Map} and {@linkplain Collection} with basic types
* {@linkplain Boolean}, {@linkplain Integer}, {@linkplain Long}, {@linkplain Double},
* {@linkplain String} and {@linkplain Date}. {@linkplain Map}s cannot contain null keys or values.
- * {@linkplain List}s can contain null elements.
+ * {@linkplain Collection}s can contain null elements.
*
* @param name the Claim's name.
* @param map the Claim's key-values.
@@ -365,34 +365,34 @@ public Builder withClaim(String name, Map map) throws IllegalArgument
assertNonNull(name);
// validate map contents
if (map != null && !validateClaim(map)) {
- throw new IllegalArgumentException("Expected map containing Map, List, Boolean, Integer, "
- + "Long, Double, String and Date");
+ throw new IllegalArgumentException("Expected map containing Map, Collection (List, Set, Queue), "
+ + "Boolean, Integer, Long, Double, String and Date");
}
addClaim(name, map);
return this;
}
/**
- * Add a custom List Claim with the given items.
+ * Add a custom Collection (can be a List, a Set or a Queue) Claim with the given items.
*
- * Accepted nested types are {@linkplain Map} and {@linkplain List} with basic types
+ * Accepted nested types are {@linkplain Map} and {@linkplain Collection} with basic types
* {@linkplain Boolean}, {@linkplain Integer}, {@linkplain Long}, {@linkplain Double},
* {@linkplain String} and {@linkplain Date}. {@linkplain Map}s cannot contain null keys or values.
- * {@linkplain List}s can contain null elements.
+ * {@linkplain Collection}s can contain null elements.
*
* @param name the Claim's name.
- * @param list the Claim's list of values.
+ * @param collection the Claim's collection of values.
* @return this same Builder instance.
- * @throws IllegalArgumentException if the name is null, or if the list contents does not validate.
+ * @throws IllegalArgumentException if the name is null, or if the collection contents does not validate.
*/
- public Builder withClaim(String name, List> list) throws IllegalArgumentException {
+ public Builder withClaim(String name, Collection> collection) throws IllegalArgumentException {
assertNonNull(name);
- // validate list contents
- if (list != null && !validateClaim(list)) {
- throw new IllegalArgumentException("Expected list containing Map, List, Boolean, Integer, "
- + "Long, Double, String and Date");
+ // validate collection contents
+ if (collection != null && !validateClaim(collection)) {
+ throw new IllegalArgumentException("Expected Collection containing Map, Collection (List, Set, Queue), "
+ + "Boolean, Integer, Long, Double, String and Date");
}
- addClaim(name, list);
+ addClaim(name, collection);
return this;
}
@@ -455,10 +455,10 @@ public Builder withArrayClaim(String name, Long[] items) throws IllegalArgumentE
* Add specific Claims to set as the Payload. If the provided map is null then
* nothing is changed.
*
- * Accepted types are {@linkplain Map} and {@linkplain List} with basic types
+ * Accepted types are {@linkplain Map} and {@linkplain Collection} with basic types
* {@linkplain Boolean}, {@linkplain Integer}, {@linkplain Long}, {@linkplain Double},
* {@linkplain String} and {@linkplain Date}.
- * {@linkplain Map}s and {@linkplain List}s can contain null elements.
+ * {@linkplain Map}s and {@linkplain Collection}s can contain null elements.
*
*
*
@@ -476,8 +476,8 @@ public Builder withPayload(Map payloadClaims) throws IllegalArgumentE
}
if (!validatePayload(payloadClaims)) {
- throw new IllegalArgumentException("Claim values must only be of types Map, List, Boolean, Integer, "
- + "Long, Double, String, Date, Instant, and Null");
+ throw new IllegalArgumentException("Claim values must only be of types Map, Collection "
+ + "(List, Set, Queue), Boolean, Integer, Long, Double, String, Date, Instant, and Null");
}
// add claims only after validating all claims so as not to corrupt the claims map of this builder
@@ -521,11 +521,15 @@ private boolean validatePayload(Map payload) {
assertNonNull(key);
Object value = entry.getValue();
- if (value instanceof List && !validateClaim((List>) value)) {
+ if (value instanceof Collection && !validateClaim((Collection>) value)) {
return false;
- } else if (value instanceof Map && !validateClaim((Map, ?>) value)) {
+ }
+
+ if (value instanceof Map && !validateClaim((Map, ?>) value)) {
return false;
- } else if (!isSupportedType(value)) {
+ }
+
+ if (!isSupportedType(value)) {
return false;
}
}
@@ -547,9 +551,9 @@ private static boolean validateClaim(Map, ?> map) {
return true;
}
- private static boolean validateClaim(List> list) {
- // accept null values in list
- for (Object object : list) {
+ private static boolean validateClaim(Collection> collection) {
+ // accept null values in collection
+ for (Object object : collection) {
if (!isSupportedType(object)) {
return false;
}
@@ -558,8 +562,8 @@ private static boolean validateClaim(List> list) {
}
private static boolean isSupportedType(Object value) {
- if (value instanceof List) {
- return validateClaim((List>) value);
+ if (value instanceof Collection) {
+ return validateClaim((Collection>) value);
} else if (value instanceof Map) {
return validateClaim((Map, ?>) value);
} else {
diff --git a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java
index 53cd267b..9ce28e3a 100644
--- a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java
+++ b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java
@@ -800,7 +800,7 @@ public void shouldOverwriteExistingPayloadWhenSettingSamePayloadKey() {
@Test
public void withPayloadShouldNotAllowCustomType() {
exception.expect(IllegalArgumentException.class);
- exception.expectMessage("Claim values must only be of types Map, List, Boolean, Integer, Long, Double, String, Date, Instant, and Null");
+ exception.expectMessage("Claim values must only be of types Map, Collection (List, Set, Queue), Boolean, Integer, Long, Double, String, Date, Instant, and Null");
Map payload = new HashMap<>();
payload.put("entry", "value");
@@ -824,10 +824,79 @@ public void withPayloadShouldAllowNullListItems() {
assertThat(payloadJson, JsonMatcher.hasEntry("list", Arrays.asList("item1", null, "item2")));
}
+ @Test
+ public void withPayloadShouldAllowCollectionInGeneral() {
+ Map payload1 = new HashMap<>();
+ Map payload2 = new HashMap<>();
+ Map payload3 = new HashMap<>();
+ Map payload4 = new HashMap<>();
+
+ Set set = new HashSet<>();
+
+ set.add("item1");
+ set.add("item2");
+
+ Queue queue = new ArrayDeque<>();
+
+ queue.add("item3");
+ queue.add("item4");
+
+ Set treeSet = new TreeSet<>();
+
+ treeSet.add("item6");
+ treeSet.add("item5");
+
+ List linkedList = new LinkedList<>(); // Can be both a queue and a list
+
+ linkedList.add("item7");
+ linkedList.add("item8");
+
+ payload1.put("set", set);
+ payload2.put("queue", queue);
+ payload3.put("treeSet", treeSet);
+ payload4.put("linkedList", linkedList);
+
+ String jwt1 = JWTCreator.init()
+ .withPayload(payload1)
+ .sign(Algorithm.HMAC256("secret"));
+
+ String jwt2 = JWTCreator.init()
+ .withPayload(payload2)
+ .sign(Algorithm.HMAC256("secret"));
+
+ String jwt3 = JWTCreator.init()
+ .withPayload(payload3)
+ .sign(Algorithm.HMAC256("secret"));
+
+ String jwt4 = JWTCreator.init()
+ .withPayload(payload4)
+ .sign(Algorithm.HMAC256("secret"));
+
+ assertThat(jwt1, is(notNullValue()));
+ String[] parts1 = jwt1.split("\\.");
+ String payloadJson1 = new String(Base64.getUrlDecoder().decode(parts1[1]), StandardCharsets.UTF_8);
+ assertThat(payloadJson1, JsonMatcher.hasEntry("set", Arrays.asList("item2", "item1"))); // HashSet does not ensure inserting order
+
+ assertThat(jwt2, is(notNullValue()));
+ String[] parts2 = jwt2.split("\\.");
+ String payloadJson2 = new String(Base64.getUrlDecoder().decode(parts2[1]), StandardCharsets.UTF_8);
+ assertThat(payloadJson2, JsonMatcher.hasEntry("queue", Arrays.asList("item3", "item4")));
+
+ assertThat(jwt3, is(notNullValue()));
+ String[] parts3 = jwt3.split("\\.");
+ String payloadJson3 = new String(Base64.getUrlDecoder().decode(parts3[1]), StandardCharsets.UTF_8);
+ assertThat(payloadJson3, JsonMatcher.hasEntry("treeSet", Arrays.asList("item5", "item6")));
+
+ assertThat(jwt4, is(notNullValue()));
+ String[] parts4 = jwt4.split("\\.");
+ String payloadJson4 = new String(Base64.getUrlDecoder().decode(parts4[1]), StandardCharsets.UTF_8);
+ assertThat(payloadJson4, JsonMatcher.hasEntry("linkedList", Arrays.asList("item7", "item8")));
+ }
+
@Test
public void withPayloadShouldNotAllowListWithCustomType() {
exception.expect(IllegalArgumentException.class);
- exception.expectMessage("Claim values must only be of types Map, List, Boolean, Integer, Long, Double, String, Date, Instant, and Null");
+ exception.expectMessage("Claim values must only be of types Map, Collection (List, Set, Queue), Boolean, Integer, Long, Double, String, Date, Instant, and Null");
Map payload = new HashMap<>();
payload.put("list", Arrays.asList("item1", new UserPojo("name", 42)));
@@ -839,7 +908,7 @@ public void withPayloadShouldNotAllowListWithCustomType() {
@Test
public void withPayloadShouldNotAllowMapWithCustomType() {
exception.expect(IllegalArgumentException.class);
- exception.expectMessage("Claim values must only be of types Map, List, Boolean, Integer, Long, Double, String, Date, Instant, and Null");
+ exception.expectMessage("Claim values must only be of types Map, Collection (List, Set, Queue), Boolean, Integer, Long, Double, String, Date, Instant, and Null");
Map payload = new HashMap<>();
payload.put("entry", "value");