Antti Hätinen created WICKET-5256:
-------------------------------------

             Summary: ResourceStreamResource does not setTextEncoding for 
StringResourceStream
                 Key: WICKET-5256
                 URL: https://issues.apache.org/jira/browse/WICKET-5256
             Project: Wicket
          Issue Type: Bug
          Components: wicket
    Affects Versions: 1.5.10
         Environment: Ubuntu 12.04, Sun JDK 1.6.0_38 64bit
            Reporter: Antti Hätinen
            Priority: Minor


During the migration from Wicket 1.4 to 1.5.10 I found out that the 
ResourceStreamResource.respond() does not set the ContentType charset if the 
resource is of type StringResourceStream. Even though the stream holds the 
charset, it is not set, although quite a few other header parameters are (well 
this is understandable because not all ResourceStreams are 
StringResourceStreams. Also, it is difficult to call the 
resource.setTextEncoding, because the current flow in 
resourceStreamRequestHandler.respond does not allow easy overriding of any 
smaller piece of respond than the whole method. The practical issue was to 
download a CSV file by clicking a button. I managed to fix the issue by 
copy/paste/Overriding the ResourceStreamRequestHandler.respond, but IMHO this 
is not nice:

    private void addCsvButton() {
        Form<?> form = new Form<Void>("form") {
            @Override
            protected void onSubmit() {
                final String fileName = getFileName("csv");
                TableCsvResourceFactory factory = new TableCsvResourceFactory();
                final IResourceStream resourceStream = 
factory.getResourceStream(tableModel.getObject());
                ResourceStreamRequestHandler resourceStreamRequestHandler = new 
ResourceStreamRequestHandler(
                        resourceStream) {
                    final ContentDisposition contentDisposition = 
ContentDisposition.ATTACHMENT;

                    @Override
                    public void respond(IRequestCycle requestCycle) {
                        Attributes attributes = new 
Attributes(requestCycle.getRequest(), requestCycle.getResponse());

                        ResourceStreamResource resource = new 
ResourceStreamResource(resourceStream);
                        resource.setFileName(fileName);
                        if (contentDisposition != null) {
                            resource.setContentDisposition(contentDisposition);
                        } else {
                            
resource.setContentDisposition(Strings.isEmpty(fileName) ? 
ContentDisposition.INLINE
                                    : ContentDisposition.ATTACHMENT);
                        }

                        final Duration cacheDuration = getCacheDuration();
                        if (cacheDuration != null) {
                            resource.setCacheDuration(cacheDuration);
                        }
+                        resource.setTextEncoding("UTF-8");

                        resource.respond(attributes);
                    }
                };
                
RequestCycle.get().scheduleRequestHandlerAfterCurrent(resourceStreamRequestHandler);
            }
        };
        form.setVisible(displayCsv);
        add(form);
    }

There are a couple of problems with the current implementation of 
ResourceStreamRequestHandler:
1) I didn't figure out yet any other way how to call the 
                        resource.setTextEncoding("UTF-8");
except by copy/pasting the whole ResourceStreamRequestHandler.respond() code to 
the Override. It would be nice, if there would be some cleaner hook to override 
some smaller part of this method, such as an empty default implementation of 
setTextEncoding() that would be always called but would not do anything for 
other types.

2) A second approach would be to create a StringResourceStreamRequestHandler 
extends ResourceStreamRequestHandler that would be otherwise the same, but 
would use IStringResource instead of IResource, and would also set the 
TextEncoding.

3) However, third, I didn't yet find any good way to get the encoding from the 
StringResourceStream itself, because the AbstractStringResourceStream has a 
protected getCharset(). This problem could be overcome by adding public version 
of getCharset() to StringResourceStream, or as I did, create a parallel 
subclass CharsetStringResourceStream that is a copy/paste from 
StringResourceStream but is non-final and has public getCharset(). After this 
you could dynamically set the text encoding in 
ResourceStreamRequestHandler.respond for example like this:

                        if (getResourceStream() instanceof 
CharsetStringResourceStream) {
                            
resource.setTextEncoding(((CharsetStringResourceStream)getResourceStream()).getCharsetName());
                        }

Anyway, I think the usage of StringResourceStream with 
ResourceStreamRequestHandler should be improved somehow, at the moment I think 
it is a bit awkward to use.


--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira

Reply via email to