Assuming you can locate Struts version which supports CollectionConverter and 
implementor DefaultTypeConverter codebase

You will of course need to code at least one testcase to make sure 
MyStringToCollectionConverter works

Once testcase is coded and works
can you submit MyStringToCollectionConverter and TestCase  as Struts patch to 
CollectionConverter code base?

Thanks Burton!
M-

________________________________
From: Burton Rhodes <burtonrho...@gmail.com>
Sent: Thursday, August 12, 2021 9:07 AM
To: Struts Users Mailing List <user@struts.apache.org>
Subject: Re: How to implement custom StrutsTypeConverter to convert String to 
Collection?

Thanks Zahid -
I've spent the better part of a day in the debugger, but ultimately figured
it out.  Essentially, I first needed to use the DefaultTypeConverter to
parse the individual elements, then use the CollectionConverter to place
the elements into the final Collection needed for the Action.  In case
anyone is interested, here is my final code that converts a comma separated
string into a collection using a custom Struts type converter:

/**
 * Converter class to convert comma separated string to a collection
*   (e.g. form input value of "[a,b,c]" -> Set<AnyClass>())
 */
public class MyStringToCollectionConverter extends DefaultTypeConverter {

    private ObjectTypeDeterminer objectTypeDeterminer;

    @Inject
    public void setObjectTypeDeterminer(ObjectTypeDeterminer determiner) {
        this.objectTypeDeterminer = determiner;
    }

    @Override
    public Object convertValue(Map<String, Object> context, Object target,
Member member, String propertyName, Object value, Class toType) {

        // Clean up and parse values into []
        String s = ((String[]) value)[0];
        String temp = s.replaceAll("[\\[\\]\"']", "");
        String[] cleanedValues = Arrays.stream(temp.split(","))
                .map(String::trim)
                .filter(StringUtils::isNotBlank)
                .toArray(String[]::new);

        // Convert values into an Object[] of "memberType"
        Class<?> memberType =
objectTypeDeterminer.getElementClass(target.getClass(), propertyName, null);
        Object[] convertedValues = Arrays.stream(cleanedValues)
                .map(val -> convertValue(val, memberType))
                .toArray();

        // Use CollectionConverter to convert values into the expected
collection
        CollectionConverter collectionConverter = new CollectionConverter();
        collectionConverter.setObjectTypeDeterminer(objectTypeDeterminer);
        return collectionConverter.convertValue(context, target, member,
propertyName, convertedValues, toType);
    }
}


On Wed, Aug 11, 2021 at 6:49 PM Zahid Rahman <zahidr1...@gmail.com> wrote:

>   > I have a html form input that submits a string value that needs to be
> converted to a java Collection.
>
> To find the bug in logic
> I would  hard code a string which is expected  from html input form.
>
> Using an IDE .
>
> Set a break point there to go into debug mode.
>
> Step through the code one step at a time.
> Watch the string values changes
> In the debug window.
> Then you can see  the  data values change as expected or not at each step.
>
>
>
>
> zahid
>
>
>
> https://www.backbutton.org
>
> ¯\_(ツ)_/¯
> ♡۶♡۶ ♡۶
>
>
> On Wed, 11 Aug 2021, 13:50 Burton Rhodes, <burtonrho...@gmail.com> wrote:
>
> > I have a html form input that submits a string value that needs to be
> > converted to a java Collection (a Set object in this case).  Specifically
> > the input key/value is: viewTasksFilter.taskStatuses="[OPEN,COMPLETE]".
> >  In the "viewTaskFilter" object, "taskStatuses" is defined as a Set with
> > enum values (Set<TaskStatus> taskStatuses).  The custom converter below
> > does convert the input form value to a Set, however it is a Set<String>
> > (not Set<TaskStatus>).  This is an issue because the Struts Action member
> > variable "viewTasksFilter.taskStatuses" now contains a Set of the wrong
> > type.  Since I will have other variables that need this logic, I would
> > prefer not to hardcode the Set<TaskStatus> in this converter.  Is there a
> > way to use existing Struts "converter code" to convert the Set<String> to
> > the appropriate Set<Object>?  I know the built-in Struts converters
> already
> > do this, but I am unable to figure out how to do this in a custom
> > converter.  Is this possible?  Or is this even the right way to solve
> this
> > issue?  Any help is appreciated!
> >
> >
> > /**
> >  * Converter class to convert comma separated string to a collection
> >  */
> > public class MyStringToCollectionConverter extends StrutsTypeConverter {
> >
> >     @Override
> >     public Object convertFromString(Map context, String[] values, Class
> > toClass) {
> >
> >         String s = values[0];
> >         String temp = s.replaceAll("[\\[\\]\"']", "");
> >         List<String> cleanedValues = Arrays.stream(temp.split(","))
> >                 .map(String::trim)
> >                 .collect(Collectors.toList());
> >
> >         if (toClass == Set.class) {
> >             try {
> >                 if (cleanedValues.size() == 0) {
> >                     return null;
> >                 } else {
> >                     return new HashSet<>(cleanedValues);
> >                 }
> >             } catch (Exception e) {
> >                 throw new TypeConversionException("Could not parse to Set
> > class:" + Arrays.toString(values));
> >             }
> >
> >         } else if (toClass == List.class) {
> >             try {
> >                 if (cleanedValues.size() == 0) {
> >                     return null;
> >                 } else {
> >                     return cleanedValues;
> >                 }
> >             } catch (Exception e) {
> >                 throw new TypeConversionException("Could not parse to
> List
> > class:" + Arrays.toString(values));
> >             }
> >
> >         }
> >
> >         return null;
> >     }
> >
> >     @Override
> >     public String convertToString(Map context, Object o) {
> >         if (o == null) {
> >             return null;
> >         } else {
> >             return o.toString();
> >         }
> >     }
> > }
> >
>

Reply via email to