33import org .apache .commons .beanutils .ConvertUtils ;
44import org .apache .commons .lang3 .StringUtils ;
55import org .jetbrains .annotations .NotNull ;
6+ import org .json .JSONArray ;
7+ import org .junit .Assert ;
8+ import org .junit .Test ;
69import org .labkey .api .collections .CaseInsensitiveHashSet ;
710import org .labkey .api .exp .property .IPropertyValidator ;
811import org .labkey .api .exp .property .PropertyService ;
912import org .labkey .api .gwt .client .model .PropertyValidatorType ;
1013import org .labkey .api .ontology .Unit ;
14+ import org .labkey .api .reader .TabLoader ;
1115import org .labkey .api .util .DOM ;
1216import org .labkey .api .util .HtmlString ;
1317import org .labkey .api .util .PageFlowUtil ;
1418import org .labkey .api .writer .HtmlWriter ;
1519
20+ import java .io .StringBufferInputStream ;
1621import java .sql .ResultSet ;
1722import java .sql .SQLException ;
1823import java .sql .Types ;
@@ -186,6 +191,7 @@ protected Array(Stream<Object> str)
186191 array = str .filter (Objects ::nonNull )
187192 .map (s -> StringUtils .trimToNull (s .toString ()))
188193 .filter (Objects ::nonNull )
194+ .filter (set ::add )
189195 .toArray (String []::new );
190196 }
191197
@@ -206,6 +212,20 @@ private List<String> getList()
206212 return list ;
207213 }
208214
215+ @ Override
216+ public boolean equals (Object obj )
217+ {
218+ if (!(obj instanceof Array arr ))
219+ return false ;
220+ return Arrays .equals (array , arr .array );
221+ }
222+
223+ @ Override
224+ public int hashCode ()
225+ {
226+ return Arrays .hashCode (array );
227+ }
228+
209229 @ Override
210230 public String toString ()
211231 {
@@ -491,13 +511,17 @@ public static Converter getInstance()
491511 public <T > T convert (Class <T > aClass , Object o )
492512 {
493513 if (null == o )
494- return (T ) List .of ();
514+ return (T ) Array .from (new String []{});
515+ if (o instanceof MultiChoice .Array arr )
516+ return (T )arr ;
495517 if (o instanceof String s )
496518 return (T ) Array .from (s );
497- if (o instanceof org .json .JSONArray json )
498- return (T ) Array .from (json );
499519 if (o .getClass ().isArray ())
500520 return (T ) Array .from ((Object []) o );
521+ if (o instanceof org .json .JSONArray json )
522+ return (T ) Array .from (json );
523+ if (o instanceof List list )
524+ return (T ) new Array (list .stream ());
501525 return (T ) Array .from (o .toString ());
502526 }
503527
@@ -507,4 +531,56 @@ final public Object apply(Object o)
507531 return convert (MultiChoice .Array .class , o );
508532 }
509533 }
534+
535+
536+
537+ public static class TestCase extends Assert
538+ {
539+ @ Test
540+ public void testConvert () throws Exception
541+ {
542+ Array expected = Array .from (new String []{"a," ,"b\" " ,"c " });
543+
544+ assertEquals (expected , _converter .convert (Array .class , expected ));
545+ assertEquals (expected , _converter .convert (Array .class , "\" a,\" ,\" b\" \" \" ,\" c \" " ));
546+ assertEquals (expected , _converter .convert (Array .class , new String []{"a," ,"b\" " ,"c " }));
547+ assertEquals (expected , _converter .convert (Array .class , List .of ("a," ,"b\" " ,"c " )));
548+ assertEquals (expected , _converter .convert (Array .class , new JSONArray (List .of ("a," ,"b\" " ,"c " ))));
549+ }
550+
551+ @ Test
552+ public void testCSV () throws Exception
553+ {
554+ Array expected = Array .from (new String []{"a," , "b\\ " , "c,d" , "e\" f" });
555+ // toString() == "a,", b\, "c,d", "e""f"
556+ assertEquals ("\" a,\" , b\\ , \" c,d\" , \" e\" \" f\" " , expected .toString ());
557+
558+ // csv/tsv with double double-quote escaping
559+ // add " around entire value, and double the "
560+ // (need to use some \" to avoid ending the """ """ block)
561+ String oneMultiValueColumn = """
562+ column
563+ ""\"a,"", b\\ , ""c,d"", ""e""\""f""\"
564+ """ ;
565+
566+ try (var csvLoader = new TabLoader .CsvFactory ().createLoader (new StringBufferInputStream (oneMultiValueColumn ), true ))
567+ {
568+ var maps = csvLoader .load ();
569+ assertEquals (1 , maps .size ());
570+ Map <String ,Object > map = maps .get (0 );
571+ assertTrue (map .get ("column" ) instanceof String );
572+ String value = (String ) map .get ("column" );
573+ assertEquals (expected , Array .from (value ));
574+ }
575+ try (var tsvLoader = new TabLoader .TsvFactory ().createLoader (new StringBufferInputStream (oneMultiValueColumn ), true ))
576+ {
577+ var maps = tsvLoader .load ();
578+ assertEquals (1 , maps .size ());
579+ Map <String ,Object > map = maps .get (0 );
580+ assertTrue (map .get ("column" ) instanceof String );
581+ String value = (String ) map .get ("column" );
582+ assertEquals (expected , Array .from (value ));
583+ }
584+ }
585+ }
510586}
0 commit comments