2929
3030import com .fasterxml .jackson .annotation .JsonGetter ;
3131import com .fasterxml .jackson .annotation .JsonInclude ;
32+ import com .fasterxml .jackson .annotation .JsonValue ;
3233
3334import org .apache .avro .reflect .Nullable ;
3435import org .joda .time .Duration ;
@@ -100,6 +101,7 @@ public static Type inferType(@Nullable Object value) {
100101 return Type .tryInferFrom (value );
101102 }
102103
104+ @ JsonValue
103105 public Collection <Item > items () {
104106 return entries .values ();
105107 }
@@ -175,6 +177,13 @@ public interface Builder {
175177 */
176178 ItemBuilder add (String key , long value );
177179
180+ /**
181+ * Register the given numeric display data if the value is not null.
182+ *
183+ * @see DisplayData.Builder#add(String, long)
184+ */
185+ ItemBuilder addIfNotNull (String key , @ Nullable Long value );
186+
178187 /**
179188 * Register the given numeric display data if the value is different than the specified default.
180189 *
@@ -189,6 +198,13 @@ public interface Builder {
189198 */
190199 ItemBuilder add (String key , double value );
191200
201+ /**
202+ * Register the given floating point display data if the value is not null.
203+ *
204+ * @see DisplayData.Builder#add(String, double)
205+ */
206+ ItemBuilder addIfNotNull (String key , @ Nullable Double value );
207+
192208 /**
193209 * Register the given floating point display data if the value is different than the specified
194210 * default.
@@ -204,6 +220,13 @@ public interface Builder {
204220 */
205221 ItemBuilder add (String key , boolean value );
206222
223+ /**
224+ * Register the given boolean display data if the value is not null.
225+ *
226+ * @see DisplayData.Builder#add(String, boolean)
227+ */
228+ ItemBuilder addIfNotNull (String key , @ Nullable Boolean value );
229+
207230 /**
208231 * Register the given boolean display data if the value is different than the specified default.
209232 *
@@ -286,6 +309,7 @@ ItemBuilder addIfNotDefault(
286309 * transform or component.
287310 *
288311 * @throws ClassCastException if the value cannot be safely cast to the specified type.
312+ *
289313 * @see DisplayData#inferType(Object)
290314 */
291315 ItemBuilder add (String key , Type type , Object value );
@@ -332,8 +356,8 @@ public static class Item {
332356 private final String key ;
333357 private final String ns ;
334358 private final Type type ;
335- private final String value ;
336- private final String shortValue ;
359+ private final Object value ;
360+ private final Object shortValue ;
337361 private final String label ;
338362 private final String url ;
339363
@@ -348,8 +372,8 @@ private Item(
348372 String namespace ,
349373 String key ,
350374 Type type ,
351- String value ,
352- String shortValue ,
375+ Object value ,
376+ Object shortValue ,
353377 String url ,
354378 String label ) {
355379 this .ns = namespace ;
@@ -384,7 +408,7 @@ public Type getType() {
384408 * Retrieve the value of the metadata item.
385409 */
386410 @ JsonGetter ("value" )
387- public String getValue () {
411+ public Object getValue () {
388412 return value ;
389413 }
390414
@@ -398,7 +422,7 @@ public String getValue() {
398422 @ JsonGetter ("shortValue" )
399423 @ JsonInclude (JsonInclude .Include .NON_NULL )
400424 @ Nullable
401- public String getShortValue () {
425+ public Object getShortValue () {
402426 return shortValue ;
403427 }
404428
@@ -540,48 +564,65 @@ public enum Type {
540564 STRING {
541565 @ Override
542566 FormattedItemValue format (Object value ) {
543- return new FormattedItemValue (value . toString ( ));
567+ return new FormattedItemValue (checkType ( value , String . class , STRING ));
544568 }
545569 },
546570 INTEGER {
547571 @ Override
548572 FormattedItemValue format (Object value ) {
549- Number number = (Number ) value ;
550- return new FormattedItemValue (Long .toString (number .longValue ()));
573+ if (value instanceof Integer ) {
574+ long l = ((Integer ) value ).longValue ();
575+ return format (l );
576+ }
577+
578+ return new FormattedItemValue (checkType (value , Long .class , INTEGER ));
551579 }
552580 },
553581 FLOAT {
554582 @ Override
555583 FormattedItemValue format (Object value ) {
556- return new FormattedItemValue (Double . toString (( Double ) value ));
584+ return new FormattedItemValue (checkType ( value , Number . class , FLOAT ));
557585 }
558586 },
559587 BOOLEAN () {
560588 @ Override
561589 FormattedItemValue format (Object value ) {
562- return new FormattedItemValue (Boolean .toString (( boolean ) value ));
590+ return new FormattedItemValue (checkType ( value , Boolean .class , BOOLEAN ));
563591 }
564592 },
565593 TIMESTAMP () {
566594 @ Override
567595 FormattedItemValue format (Object value ) {
568- return new FormattedItemValue ((TIMESTAMP_FORMATTER .print ((Instant ) value )));
596+ Instant instant = checkType (value , Instant .class , TIMESTAMP );
597+ return new FormattedItemValue ((TIMESTAMP_FORMATTER .print (instant )));
569598 }
570599 },
571600 DURATION {
572601 @ Override
573602 FormattedItemValue format (Object value ) {
574- return new FormattedItemValue (Long .toString (((Duration ) value ).getMillis ()));
603+ Duration duration = checkType (value , Duration .class , DURATION );
604+ return new FormattedItemValue (duration .getMillis ());
575605 }
576606 },
577607 JAVA_CLASS {
578608 @ Override
579609 FormattedItemValue format (Object value ) {
580- Class <?> clazz = ( Class <?>) value ;
610+ Class <?> clazz = checkType ( value , Class . class , JAVA_CLASS ) ;
581611 return new FormattedItemValue (clazz .getName (), clazz .getSimpleName ());
582612 }
583613 };
584614
615+ private static <T > T checkType (Object value , Class <T > clazz , DisplayData .Type expectedType ) {
616+ if (!clazz .isAssignableFrom (value .getClass ())) {
617+ throw new ClassCastException (String .format (
618+ "Value is not valid for DisplayData type %s: %s" , expectedType , value ));
619+ }
620+
621+ @ SuppressWarnings ("unchecked" ) // type checked above.
622+ T typedValue = (T ) value ;
623+ return typedValue ;
624+ }
625+
585626 /**
586627 * Format the display metadata value into a long string representation, and optionally
587628 * a shorter representation for display.
@@ -592,7 +633,6 @@ FormattedItemValue format(Object value) {
592633
593634 @ Nullable
594635 private static Type tryInferFrom (@ Nullable Object value ) {
595- Type type ;
596636 if (value instanceof Integer || value instanceof Long ) {
597637 return INTEGER ;
598638 } else if (value instanceof Double || value instanceof Float ) {
@@ -614,23 +654,23 @@ private static Type tryInferFrom(@Nullable Object value) {
614654 }
615655
616656 static class FormattedItemValue {
617- private final String shortValue ;
618- private final String longValue ;
657+ private final Object shortValue ;
658+ private final Object longValue ;
619659
620- private FormattedItemValue (String longValue ) {
660+ private FormattedItemValue (Object longValue ) {
621661 this (longValue , null );
622662 }
623663
624- private FormattedItemValue (String longValue , String shortValue ) {
664+ private FormattedItemValue (Object longValue , Object shortValue ) {
625665 this .longValue = longValue ;
626666 this .shortValue = shortValue ;
627667 }
628668
629- String getLongValue () {
669+ Object getLongValue () {
630670 return this .longValue ;
631671 }
632672
633- String getShortValue () {
673+ Object getShortValue () {
634674 return this .shortValue ;
635675 }
636676 }
@@ -700,29 +740,44 @@ public ItemBuilder add(String key, long value) {
700740 return addItemIf (true , key , Type .INTEGER , value );
701741 }
702742
743+ @ Override
744+ public ItemBuilder addIfNotNull (String key , @ Nullable Long value ) {
745+ return addItemIf (value != null , key , Type .INTEGER , value );
746+ }
747+
703748 @ Override
704749 public ItemBuilder addIfNotDefault (String key , long value , long defaultValue ) {
705- return addItemIf (value != defaultValue , key , Type .INTEGER , value );
750+ return addItemIf (! Objects . equals ( value , defaultValue ) , key , Type .INTEGER , value );
706751 }
707752
708753 @ Override
709754 public ItemBuilder add (String key , double value ) {
710755 return addItemIf (true , key , Type .FLOAT , value );
711756 }
712757
758+ @ Override
759+ public ItemBuilder addIfNotNull (String key , @ Nullable Double value ) {
760+ return addItemIf (value != null , key , Type .FLOAT , value );
761+ }
762+
713763 @ Override
714764 public ItemBuilder addIfNotDefault (String key , double value , double defaultValue ) {
715- return addItemIf (value != defaultValue , key , Type .FLOAT , value );
765+ return addItemIf (! Objects . equals ( value , defaultValue ) , key , Type .FLOAT , value );
716766 }
717767
718768 @ Override
719769 public ItemBuilder add (String key , boolean value ) {
720770 return addItemIf (true , key , Type .BOOLEAN , value );
721771 }
722772
773+ @ Override
774+ public ItemBuilder addIfNotNull (String key , @ Nullable Boolean value ) {
775+ return addItemIf (value != null , key , Type .BOOLEAN , value );
776+ }
777+
723778 @ Override
724779 public ItemBuilder addIfNotDefault (String key , boolean value , boolean defaultValue ) {
725- return addItemIf (value != defaultValue , key , Type .BOOLEAN , value );
780+ return addItemIf (! Objects . equals ( value , defaultValue ) , key , Type .BOOLEAN , value );
726781 }
727782
728783 @ Override
0 commit comments