Hell Boy
Hell Boy

Reputation: 899

How to process a string with 823237 characters

I have a string that has 823237 characters in it. its actually an xml file and for testing purpose I want to return as a response form a servlet.

I have tried everything I can possible think of

1) creating a constant with the whole string... in this case Eclipse complains (with a red line under servlet class name) -

 The type generates a string that requires more than 65535 bytes to encode in Utf8 format in the constant pool

2) breaking the whole string into 20 string constants and writing to the out object directly something like :

out.println( CONSTANT_STRING_PART_1 + CONSTANT_STRING_PART_2 + 
             CONSTANT_STRING_PART_3 + CONSTANT_STRING_PART_4 +
             CONSTANT_STRING_PART_5 + CONSTANT_STRING_PART_6 + 
     // add all the string constants till .... CONSTANT_STRING_PART_20); 

in this case ... the build fails .. complaining..

   [javac] D:\xx\xxx\xxx.java:87: constant string too long
   [javac]      CONSTANT_STRING_PART_19 + CONSTANT_STRING_PART_20); 
                                                    ^

3) reading the xml file as a string and writing to out object .. in this case I get

SEVERE: Allocate exception for servlet MyServlet
Caused by: org.apache.xmlbeans.XmlException: error: Content is not allowed in prolog.

Finally my question is ... how can I return such a big string (as response) from the servlet ???

Upvotes: 3

Views: 15530

Answers (6)

Skynin
Skynin

Reputation: 21

Ropes: Theory and practice

Why and when to use Ropes for Java for string manipulations

Upvotes: 2

Houcem Berrayana
Houcem Berrayana

Reputation: 3080

You have to deal with ByteArrayOutputStream and not with the String it self. If you want to send your String in the http response all you have to do is to read from that byteArray stream and write in the response stream like this :

ByteArrayOutputStream baos = new ByteArrayOutputStream(8232237);
baos.write(constant1.getBytes());
baos.write(constant2.getBytes());
...
baos.writeTo(response.getOutputStream());

Upvotes: 1

Teg
Teg

Reputation: 1302

You can avoid to load all the text in memory using streams:

    InputStream is = new FileInputStream("path/to/your/file"); //or the following line if the file is in the classpath
    InputStream is = MyServlet.class.getResourceAsStream("path/to/file/in/classpath");
    byte[] buff = new byte[4 * 1024];
    int read;  
    while ((read = is.read(buff)) != -1) {  
        out.write(buff, 0, read);  
    }

Upvotes: 7

Stephen C
Stephen C

Reputation: 718768

Both problem 1) and 2) are due to the same fundamental issue. A String literal (or constant String expression) cannot be more than 65535 characters because there is a hard limit on string constants in the class file format.

The third problem sounds like a bug in the way you've implemented it rather than a fundamental problem. In fact, it sounds like you are trying to load the XML as a DOM and then unparse it (which is unnecessary), and that somehow you have managed to mangle the XML in the process. (Or maybe it is mangled in the file you are trying to read ...)

The simple and elegant solution is to save the stuff in a file, and then read it as plain text.

Or ... less elegant, but just as effective:

   String[] strings = new String[](
        "longString1",
        "longString2",
        ...
        "longStringN"};

   for (String str : strings) {
       out.write(str);
   }

Of course, the problem with embedding test data as string literals is that you have to escape certain characters in the string to keep the compiler happy. That's tedious if you have to do it by hand.

Upvotes: 0

brimborium
brimborium

Reputation: 9512

The second approach might work the following way:

out.print(CONSTANT_STRING_PART_1);
out.print(CONSTANT_STRING_PART_2);
out.print(CONSTANT_STRING_PART_3);
out.print(CONSTANT_STRING_PART_4);
// ...
out.print(CONSTANT_STRING_PART_N);
out.println();

You can do this in a loop of course (which is highly recommended ;)).

The way you do it, you just temporarely create the large string again to then pass it to println(), which is the same problem as the first one.

Upvotes: 4

Thilo
Thilo

Reputation: 262494

You can read a 823K file into a String. Maybe not the most elegant method, but totally doable. Method 3 should have worked. There was an XML error, but that has nothing to do with reading from a file into a String, or the length of the data.

It has to be an external file, though, because it is too big to be inlined into a class file (there are size limits for those).

I recommend Commons IO FileUtils#readFileToString.

Upvotes: 1

Related Questions