1515 * A {@code LDUser} object contains specific attributes of a user browsing your site. The only mandatory property property is the {@code key},
1616 * which must uniquely identify each user. For authenticated users, this may be a username or e-mail address. For anonymous users,
1717 * this could be an IP address or session ID.
18- *
18+ * <p>
1919 * Besides the mandatory {@code key}, {@code LDUser} supports two kinds of optional attributes: interpreted attributes (e.g. {@code ip} and {@code country})
2020 * and custom attributes. LaunchDarkly can parse interpreted attributes and attach meaning to them. For example, from an {@code ip} address, LaunchDarkly can
2121 * do a geo IP lookup and determine the user's country.
22- *
22+ * <p>
2323 * Custom attributes are not parsed by LaunchDarkly. They can be used in custom rules-- for example, a custom attribute such as "customer_ranking" can be used to
2424 * launch a feature to the top 10% of users on a site.
2525 */
@@ -43,21 +43,22 @@ public class LDUser {
4343 }
4444
4545 protected LDUser (Builder builder ) {
46- this .key = builder .key == null ? null : new JsonPrimitive (builder .key );
47- this .ip = builder .ip == null ? null : new JsonPrimitive (builder .ip );
48- this .country = builder .country == null ? null : new JsonPrimitive (builder .country .getAlpha2 ());
46+ this .key = builder .key == null ? null : new JsonPrimitive (builder .key );
47+ this .ip = builder .ip == null ? null : new JsonPrimitive (builder .ip );
48+ this .country = builder .country == null ? null : new JsonPrimitive (builder .country .getAlpha2 ());
4949 this .secondary = builder .secondary == null ? null : new JsonPrimitive (builder .secondary );
5050 this .firstName = builder .firstName == null ? null : new JsonPrimitive (builder .firstName );
5151 this .lastName = builder .lastName == null ? null : new JsonPrimitive (builder .lastName );
5252 this .email = builder .email == null ? null : new JsonPrimitive (builder .email );
5353 this .name = builder .name == null ? null : new JsonPrimitive (builder .name );
5454 this .avatar = builder .avatar == null ? null : new JsonPrimitive (builder .avatar );
55- this .anonymous = builder .anonymous == null ? null : new JsonPrimitive (builder .anonymous );
55+ this .anonymous = builder .anonymous == null ? null : new JsonPrimitive (builder .anonymous );
5656 this .custom = new HashMap <>(builder .custom );
5757 }
5858
5959 /**
6060 * Create a user with the given key
61+ *
6162 * @param key a {@code String} that uniquely identifies a user
6263 */
6364 public LDUser (String key ) {
@@ -69,23 +70,41 @@ JsonPrimitive getKey() {
6970 return key ;
7071 }
7172
72- JsonPrimitive getIp () { return ip ; }
73+ JsonPrimitive getIp () {
74+ return ip ;
75+ }
7376
74- JsonPrimitive getCountry () { return country ; }
77+ JsonPrimitive getCountry () {
78+ return country ;
79+ }
7580
76- JsonPrimitive getSecondary () { return secondary ; }
81+ JsonPrimitive getSecondary () {
82+ return secondary ;
83+ }
7784
78- JsonPrimitive getName () { return name ; }
85+ JsonPrimitive getName () {
86+ return name ;
87+ }
7988
80- JsonPrimitive getFirstName () { return firstName ; }
89+ JsonPrimitive getFirstName () {
90+ return firstName ;
91+ }
8192
82- JsonPrimitive getLastName () { return lastName ; }
93+ JsonPrimitive getLastName () {
94+ return lastName ;
95+ }
8396
84- JsonPrimitive getEmail () { return email ; }
97+ JsonPrimitive getEmail () {
98+ return email ;
99+ }
85100
86- JsonPrimitive getAvatar () { return avatar ; }
101+ JsonPrimitive getAvatar () {
102+ return avatar ;
103+ }
87104
88- JsonPrimitive getAnonymous () { return anonymous ; }
105+ JsonPrimitive getAnonymous () {
106+ return anonymous ;
107+ }
89108
90109 JsonElement getCustom (String key ) {
91110 return custom .get (key );
@@ -94,14 +113,13 @@ JsonElement getCustom(String key) {
94113 /**
95114 * A <a href="http://en.wikipedia.org/wiki/Builder_pattern">builder</a> that helps construct {@link com.launchdarkly.client.LDUser} objects. Builder
96115 * calls can be chained, enabling the following pattern:
97- *
116+ * <p>
98117 * <pre>
99118 * LDUser user = new LDUser.Builder("key")
100119 * .country("US")
101120 * .ip("192.168.0.1")
102121 * .build()
103122 * </pre>
104- *
105123 */
106124 public static class Builder {
107125 private String key ;
@@ -118,6 +136,7 @@ public static class Builder {
118136
119137 /**
120138 * Create a builder with the specified key
139+ *
121140 * @param key the unique key for this user
122141 */
123142 public Builder (String key ) {
@@ -127,6 +146,7 @@ public Builder(String key) {
127146
128147 /**
129148 * Set the IP for a user
149+ *
130150 * @param s the IP address for the user
131151 * @return the builder
132152 */
@@ -144,6 +164,7 @@ public Builder secondary(String s) {
144164 * Set the country for a user. The country should be a valid <a href="http://en.wikipedia.org/wiki/ISO_3166-1">ISO 3166-1</a>
145165 * alpha-2 or alpha-3 code. If it is not a valid ISO-3166-1 code, an attempt will be made to look up the country by its name.
146166 * If that fails, a warning will be logged, and the country will not be set.
167+ *
147168 * @param s the country for the user
148169 * @return the builder
149170 */
@@ -155,8 +176,7 @@ public Builder country(String s) {
155176
156177 if (codes .isEmpty ()) {
157178 logger .warn ("Invalid country. Expected valid ISO-3166-1 code: " + s );
158- }
159- else if (codes .size () > 1 ) {
179+ } else if (codes .size () > 1 ) {
160180 // See if any of the codes is an exact match
161181 for (LDCountryCode c : codes ) {
162182 if (c .getName ().equals (s )) {
@@ -166,8 +186,7 @@ else if (codes.size() > 1) {
166186 }
167187 logger .warn ("Ambiguous country. Provided code matches multiple countries: " + s );
168188 country = codes .get (0 );
169- }
170- else {
189+ } else {
171190 country = codes .get (0 );
172191 }
173192
@@ -188,6 +207,7 @@ public Builder country(LDCountryCode country) {
188207
189208 /**
190209 * Sets the user's first name
210+ *
191211 * @param firstName the user's first name
192212 * @return the builder
193213 */
@@ -198,6 +218,7 @@ public Builder firstName(String firstName) {
198218
199219 /**
200220 * Sets whether this user is anonymous
221+ *
201222 * @param anonymous whether the user is anonymous
202223 * @return the builder
203224 */
@@ -208,6 +229,7 @@ public Builder anonymous(boolean anonymous) {
208229
209230 /**
210231 * Sets the user's last name
232+ *
211233 * @param lastName the user's last name
212234 * @return the builder
213235 */
@@ -218,6 +240,7 @@ public Builder lastName(String lastName) {
218240
219241 /**
220242 * Sets the user's full name
243+ *
221244 * @param name the user's full name
222245 * @return the builder
223246 */
@@ -228,6 +251,7 @@ public Builder name(String name) {
228251
229252 /**
230253 * Sets the user's avatar
254+ *
231255 * @param avatar the user's avatar
232256 * @return the builder
233257 */
@@ -238,6 +262,7 @@ public Builder avatar(String avatar) {
238262
239263 /**
240264 * Sets the user's e-mail address
265+ *
241266 * @param email the e-mail address
242267 * @return the builder
243268 */
@@ -248,61 +273,71 @@ public Builder email(String email) {
248273
249274 /**
250275 * Add a {@link java.lang.String}-valued custom attribute.
276+ *
251277 * @param k the key for the custom attribute. When set to one of the built-in user attribute keys, this custom attribute will be ignored.
252278 * @param v the value for the custom attribute
253279 * @return the builder
254280 */
255281 public Builder custom (String k , String v ) {
256- if (key != null && v != null ) {
282+ checkCustomAttribute (k );
283+ if (k != null && v != null ) {
257284 custom .put (k , new JsonPrimitive (v ));
258285 }
259286 return this ;
260287 }
261288
262289 /**
263290 * Add a {@link java.lang.Number}-valued custom attribute
291+ *
264292 * @param k the key for the custom attribute. When set to one of the built-in user attribute keys, this custom attribute will be ignored.
265293 * @param n the value for the custom attribute
266294 * @return the builder
267295 */
268296 public Builder custom (String k , Number n ) {
269- if (key != null && n != null ) {
297+ checkCustomAttribute (k );
298+ if (k != null && n != null ) {
270299 custom .put (k , new JsonPrimitive (n ));
271300 }
272301 return this ;
273302 }
274303
275304 /**
276305 * Add a {@link java.lang.Boolean}-valued custom attribute
306+ *
277307 * @param k the key for the custom attribute. When set to one of the built-in user attribute keys, this custom attribute will be ignored.
278308 * @param b the value for the custom attribute
279309 * @return the builder
280310 */
281311 public Builder custom (String k , Boolean b ) {
282- if (key != null && b != null ) {
312+ checkCustomAttribute (k );
313+ if (k != null && b != null ) {
283314 custom .put (k , new JsonPrimitive (b ));
284315 }
285316 return this ;
286317 }
287318
288319 /**
289320 * Add a list of {@link java.lang.String}-valued custom attributes
290- * @param k the key for the list. When set to one of the built-in user attribute keys, this custom attribute will be ignored.
321+ *
322+ * @param k the key for the list. When set to one of the built-in user attribute keys, this custom attribute will be ignored.
291323 * @param vs the values for the attribute
292324 * @return the builder
293325 * @deprecated As of version 0.16.0, renamed to {@link #customString(String, List) customString}
294326 */
295327 public Builder custom (String k , List <String > vs ) {
328+ checkCustomAttribute (k );
296329 return this .customString (k , vs );
297330 }
298-
331+
299332 /**
300333 * Add a list of {@link java.lang.String}-valued custom attributes
301- * @param k the key for the list. When set to one of the built-in user attribute keys, this custom attribute will be ignored.
334+ *
335+ * @param k the key for the list. When set to one of the built-in user attribute keys, this custom attribute will be ignored.
302336 * @param vs the values for the attribute
303337 * @return the builder
304338 */
305339 public Builder customString (String k , List <String > vs ) {
340+ checkCustomAttribute (k );
306341 JsonArray array = new JsonArray ();
307342 for (String v : vs ) {
308343 if (v != null ) {
@@ -312,14 +347,16 @@ public Builder customString(String k, List<String> vs) {
312347 custom .put (k , array );
313348 return this ;
314349 }
315-
350+
316351 /**
317352 * Add a list of {@link java.lang.Integer}-valued custom attributes
318- * @param k the key for the list. When set to one of the built-in user attribute keys, this custom attribute will be ignored.
353+ *
354+ * @param k the key for the list. When set to one of the built-in user attribute keys, this custom attribute will be ignored.
319355 * @param vs the values for the attribute
320356 * @return the builder
321357 */
322358 public Builder customNumber (String k , List <Number > vs ) {
359+ checkCustomAttribute (k );
323360 JsonArray array = new JsonArray ();
324361 for (Number v : vs ) {
325362 if (v != null ) {
@@ -330,8 +367,18 @@ public Builder customNumber(String k, List<Number> vs) {
330367 return this ;
331368 }
332369
370+ private void checkCustomAttribute (String key ) {
371+ for (UserAttribute a : UserAttribute .values ()) {
372+ if (a .name ().equals (key )) {
373+ logger .warn ("Built-in attribute key: " + key + " added as custom attribute! This custom attribute will be ignored during Feature Flag evaluation" );
374+ return ;
375+ }
376+ }
377+ }
378+
333379 /**
334380 * Build the configured {@link com.launchdarkly.client.LDUser} object
381+ *
335382 * @return the {@link com.launchdarkly.client.LDUser} configured by this builder
336383 */
337384 public LDUser build () {
0 commit comments