I have my own little serialiser class
package mypackage.shared;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class Serializer {
static final String HEXES = "0123456789ABCDEF";
public static String serialize(Object o) throws IOException {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(stream);
os.writeObject(o);
os.close();
return toHex(stream.toByteArray());
}
public static Object deserialize(String hexString) throws IOException, ClassNotFoundException {
byte[] serializedBytes = toByteArray(hexString);
ByteArrayInputStream bis = new ByteArrayInputStream(serializedBytes);
ObjectInputStream ois = new ObjectInputStream(bis);
Object o = null;
o = ois.readObject();
ois.close();
return o;
}
public static String toHex( byte [] raw ) {
if ( raw == null ) {
return null;
}
final StringBuilder hex = new StringBuilder( 2 * raw.length );
for ( final byte b : raw ) {
hex.append(HEXES.charAt((b & 0xF0) >> 4))
.append(HEXES.charAt((b & 0x0F)));
}
return hex.toString();
}
private static byte[] toByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
}
It works great for some home made objects I have. However, as soon as I have an ArrayList of these objects it fails to deserialize them. ANy idea why that would be? I find it quite hard to debug since readObject() just fails
If serialization doesn't work it means that some object is not serializable.
Try to deserialize an arraylist containing only one home object and do it for all home objects
Related
I have a StringBuilder (~1GB size) which converts to an almost 1GB String. Then it is sent to AWSS3Client to be put as a file on s3. Now to write the String to s3, I need to further convert the string to a ByteArrayInputStream, which takes another 1GB.
InputStream dataInputStream = new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8));
amazonS3Client.putObject(bucket, key, dataInputStream, new ObjectMetadata());
Now I end up with a JVM heap of 3GB. Is there a way to directly send the 1GB StringBuilder directly to S3 with little over 1GB heap?
The only way I could think of is to convert StringBuilder to a File instance (using FileWriter) --> S3 API which takes File as input. But this approach requires a 2-IOPS to the SSD -- penalty that I want to avoid.
Any better way to handle the problem is welcome.
[edit 1]
(as per comments) The builder size changed from 5GB to 1GB. I wanted to convey that the builderis a huge one (and hence used 5GB previously, which was my mistake)
The string-oriented classes are frustratingly locked down with final in many cases, which means that oftentimes buffers that already exist in memory have to be duplicated. This is probably to do with security but is nevertheless wasteful and frustrating. You should be able to do something with the following if you have a StringBuilder. Obviously you'll need a much bigger buffer than in the illustrative main method.
import java.io.ByteArrayInputStream;
import java.io.FilterInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.Charset;
import java.util.Objects;
/**
*
* #author CEHJ
* #version 1.0
*/
public class CharSequenceInputStream extends InputStream {
private CharSequence charSequence;
private int position;
private CharsetEncoder enc;
private Charset outputEncoding;
private CharBuffer cb;
private ByteBuffer bb;
public CharSequenceInputStream(CharSequence charSequence) {
this(charSequence, Charset.forName(System.getProperty("native.encoding", Charset.defaultCharset().name())));
}
public CharSequenceInputStream(CharSequence charSequence, Charset outputEncoding) {
this.charSequence = charSequence;
this.outputEncoding = outputEncoding;
position = 0;
enc = outputEncoding.newEncoder();
cb = CharBuffer.allocate(1);
bb = ByteBuffer.allocate(8);
}
// For testing only
public static void main(String[] args) throws IOException {
if (args.length < 2) {
System.err.printf("Usage: java CharSequenceInputStream <String to be stored> <Output file> [Char encoding for output]");
System.exit(1);
}
String content = args[0];
String outputPath = args[1];
StringBuilder sb = new StringBuilder(content);
CharSequenceInputStream in = null;
if (args.length > 2) {
in = new CharSequenceInputStream(sb, Charset.forName(args[2]));
} else {
in = new CharSequenceInputStream(sb);
}
try (OutputStream out = new FileOutputStream(outputPath)) {
int bytesRead = -1;
final int BUF_SIZE = 8;
byte[] buf = new byte[BUF_SIZE];
while ((bytesRead = in.read(buf, 0, BUF_SIZE)) > -1) {
out.write(buf, 0, bytesRead);
}
}
}
#Override
public int read() throws IOException {
int result = -1;
if (position < charSequence.length()) {
if (bb.remaining() == bb.capacity() || bb.position() == bb.limit()) {
// At start - nothing yet has been decoded
// OR - we've read all bytes in the buffer and need to refill it
cb.clear();
bb.clear();
char currentChar = charSequence.charAt(position++);
cb.append(currentChar);
cb.flip();
enc.reset();
enc.encode(cb, bb, false);
enc.encode(cb, bb, true);
enc.flush(bb);
bb.flip();
}
}
if (bb.position() < bb.limit()) {
result = bb.get() & 0xFF;
}
return result;
}
#Override
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
#Override
public int read(byte b[], int off, int len) throws IOException {
Objects.checkFromIndexSize(off, len, b.length);
if (len == 0) {
return 0;
}
int c = read();
if (c == -1) {
return -1;
}
b[off] = (byte) c;
int i = 1;
try {
for (; i < len; i++) {
c = read();
if (c == -1) {
break;
}
b[off + i] = (byte) c;
}
} catch (IOException ee) {
}
return i;
}
#Override
public void close() {
// NO OP
}
}
This is my first time touching Java in a few years. I have been tasked with creating a runnable Jar file which will be called to communicate with an RFID card reader. Now, my code steps through fine in Debug mode, however, when I simply try to run the programme, I'm hit with a NullPointerException. Excuse me if the answer is obvious, but its been a while since I touched Java.
I'm using Eclipse IDE (2019)
Any help would be most appreciated
package rfid;
import jssc.SerialPort;
import jssc.SerialPortException;
import jssc.SerialPortList;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Formatter;
import javax.xml.bind.DatatypeConverter;
public class RFID_TEST {
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}// for
return data;
} // hexStringToByteArray
public static String[] reverse(String[] nums) {
String[] reversed = new String[nums.length];
for (int i=0; i<nums.length; i++) {
reversed[i] = nums[nums.length - 1 - i];
}
return reversed;
}
static String byteToHex(final byte[] hash)
{
Formatter formatter = new Formatter();
for (byte b : hash)
{
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
}
public static void main (String[] args) {
String[] portNames = SerialPortList.getPortNames();
for(int i = 0; i < portNames.length; i++) {
System.out.println(portNames[i]);
}
String portReader2 = "";
SerialPort serialPort = new SerialPort("COM4");
try {
serialPort.openPort();//Open serial port
serialPort.setParams(38400,8,1,0);
byte[] bytesToSend = new byte[] {};
bytesToSend = hexStringToByteArray("020008010000020001aa550000b463");
serialPort.writeBytes(bytesToSend);//Write data to port
byte[] portReader = new byte[] {};
portReader = serialPort.readBytes();// read response
//portReader2 = DatatypeConverter.printHexBinary(portReader);
portReader2 = byteToHex(portReader);
System.out.println(portReader2);
String portReader3 = portReader2.substring(22, 36);
System.out.println(portReader3);
String[] array= portReader3.split("(?<=\\G.{2})");
System.out.println(java.util.Arrays.toString(array));
String[] finalArray = reverse(array);
String str="";
for(int i=0;i<finalArray.length;i++)
str+=finalArray[i];
String finalOne = str.replaceAll("\\s+","");
BigInteger hex = new BigInteger(finalOne, 16);
System.out.println(hex);
serialPort.closePort();//Close serial port
}
catch (SerialPortException ex) {
System.out.println(ex);
}
}
}
However, when running out of debug mode I am hit with the following NullPointerException
COM3
COM4
Exception in thread "main" java.lang.NullPointerException
at rfid.RFID_TEST.byteToHex(RFID_TEST.java:36)
at rfid.RFID_TEST.main(RFID_TEST.java:65)
I solved the issue (as directed by mwarren) by editing the portReader variable to the code below:
try {
portReader = serialPort.readBytes(28,100);
} catch (SerialPortTimeoutException e) {
e.printStackTrace();
}// read response
I'm trying to repeat in .NET the algorithm that was originally written in Java and I'm having troubles with the GZIP decompression.
At the bottom of the post I inserted the hex string that is converted to byte array in both .NET and Java. The resulting byte array is then decompressed in Java with the following method:
public static Object readObjectFromByte(byte[] bytes)
{
ObjectInputStream oos = null;
try {
ByteArrayInputStream baos = new ByteArrayInputStream(bytes);
zis = new GZIPInputStream(baos);
oos = new ObjectInputStream(zis);
return oos.readObject();
} catch (Throwable t) { GZIPInputStream zis;
return null;
} finally {
try {
if (oos != null) {
oos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
After decompression the resulting byte array has a length of 3952 which is probably correct. At the same time I tried different .NET classes/libs to decompress, but it always gives a byte array of 3979 bytes which is probably incorrect.
I tried:
GZipStream
DotNetZip
SevenZipLib
SharpZipLib
I read a lot of articles about GZIP issues in .NET trying to fix this. I use .NET 4.5, and for example my last decompression version is this:
Ionic.Zlib.GZipStream.UncompressBuffer(compressedBytes)
It's weird but even if I try:
Ionic.Zlib.GZipStream.CompressBuffer(Ionic.Zlib.GZipStream.UncompressBuffer(compressedBytes)).SequenceEquals(compressedBytes)
It gives me FALSE.
The hex string:
EDIT:
Java Code:
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
public class JavaFiddle
{
public static void main(String[] args)
{
String hex = "PLEASE_UPDATE"; //update this from the hex constant at the end of the post
byte[] compressedBytes = hexStringToByteArray(hex);
byte[] decompressedBytes = (byte[])readObjectFromByte(compressedBytes);
System.out.println(decompressedBytes.length); //THIS GIVES 3952
}
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
public static Object readObjectFromByte(byte[] bytes)
{
ObjectInputStream oos = null;
try {
ByteArrayInputStream baos = new ByteArrayInputStream(bytes);
GZIPInputStream zis = new GZIPInputStream(baos);
oos = new ObjectInputStream(zis);
return oos.readObject();
} catch (Throwable t) { GZIPInputStream zis;
return null;
} finally {
try {
if (oos != null) {
oos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
.NET Code
private byte[] StringToByteArray(string hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
return bytes;
}
...
var hex = "PLEASE_UPDATE"; //update this from the hex constant at the end of the post
var compressedBytes = StringToByteArray(hex);
var decompressedBytes = Ionic.Zlib.GZipStream.UncompressBuffer(compressedBytes);
//decompressedBytes.Length is 3979, Note that this is using one of the external libraries, the same result is for built-in GZipStream in .NET
1F8B0800000000000000ADCEF923130A0000E0596C8A1CB90AA1D0E428916C4AE6889C61071E1D2A77B42C67D1731BF2DE6C662C5744C6DE7BC8DC4791DCB79E35315EC2C62437E1FDBE9FF7FD055FC53240282418007437AB5893DB060923594000201C030088639882D19C31C860FB7838A60DBBF039C3B41821FF606044C89D24EB4C1D6A627FBF8E978D3616796C2ACDD165ABB32B81A0C493A35F163889E74665A9341C7C36F06FA0F991201BEAAB6A47842C43A50DA6B8C000AD794840CF03E29A527D0C921FAE6D607C71AEF7C01DB34037A7F8CDD8CB1F61DB9C15A87DBBDD1F933FDF58312B054D7B5AF72FE75A0AA101714EEA6980BF405A15A1F13A0979FB5BBE1636A367CB4C943FB7F87A3245573BB6857DA6AA0B412CCB553B39E06973EB2A3864E98915E46C16E4EE06E9DA63DB642915AF6E86811FD2C8F3A1F325C82677EA701D1E3574885696DEB3B8A0C29AE1FDD41DA26C55C6381506A3CF77DD15BD37783F545F76E8DCF9FB6A8B0776E2427FBFF431B73748CE96786EA569E307B5DC8990A68A52838D9DC1BA19291F283BF2C7EE43D3E4516D77A07FDE04934BB7C254057BDFC3AD153A0A711E7EFDDDED31AED367FAAEA6F494A55E029BF6AECA9433CA7D45B52EC24BCF9074315BFE5F5494F4F0DDDE8D73F56397A0667992950E62AD4020A4102DBE7C4D6B85E457F184DC5AA51D2D536313E1E16636928BD6500207571B83C8830DB9E7CF2C92AE4DDB12B8DF3C6AAF83B09CAACB78AA78CDB0DB393D71A599F185B413BFDB907FC99598D2E56ADE701EE72DB71C9650E820DB452F7DD4904E4679FFD0CB6FEEDF7527AF21BE5A5404B8BAE4E9951AE5C88BF9B5D5FFC6447989445C7A2DB80B3E4A2DBCB51978BA1729F97BDCAD174D345417B96941BF2CC5C10539C952B2526770BA4637A5820DCF150E16AED3159AD9724A8DFCFEA8BADA2A08BD1A0C9B05B019CE61E01EDECF7F028B466E4B53A5F1FAE56CB137EF269E1946896D1A3DDCDB756364A96D8E47F3FB33E9B70BBED37FA8719F2D2EA89BBFB0CAFB71CC56947F7907439E9FE97C61D2A326F830592509674860BA7CC7E713EFD69D2724DED740A2959846CFE801B313BB1DAB45594D70E888F2A3063C67085BFDB345D64D116372F5BE42BB08ABBC6D65D90E1E50C849EDD9A6F977751C4DB5A454C66B997D6A0CA148827E03AEE30F1697392124A8C44C6A914C3C69C21447F9C5660665C5D0D3F758D57086D0938608E9BECE9BA95D359C41E255B0524C55EDC97816A76E32B29BF55BAE0EC1F71DBF3FF548DC2C181755D85ABCAFEDF23C248EF7D3C1580AB88D28CDCF9935F1DA797145A7F0B18603C1DA39EA8E969A2279F20F077E7F62BD5C1F7C095BF1B21D36561A254836F37EBC0AEB8C8EAE8EC725044EE47F107DE413DE804EED41473E4D3BEC93E9234255F9FDD1FD91F00B32BF13B2629C4373888813E5FD08F66AB7295D281E180ACE99A77952DE6DCD675B20E021A71E91F78B899A1FC2F8FD913C0E4D980B1D6CF13F7A76E823BDF75FDE8FC513C3C491F51305F1A483B81A11884254CB2DB396F864B08DDEDD005A90EF457E7F8EDFB64FF7C7443C6E2135183619ED69F27E1464BF862FB14A66509C379818517F6B2423D0D1BE794E4D9C7130D9F54AB19DDF9FC825CF8B3B5EBD8090811D372C0315CEFBB926701AC2B84CB4820D25DD2D71F2F6630FB3FA88A3EAAF9E44C709EFACC05FF2FBD342E844AB8A22F433B7C2161FEDE70BF07EF29A6B6355DAF2D33E7A2679C8A38511939EEE73DABDE98B021A9F0E21A5CFFEE6F7A7C44CE2358158F5B15F837CE96B75622FEFE702653D87222B9319D46D321EEDA628713D1B355A30E0D07A655F12A55B6397CFEFCFA3DB3B76DB80347FDCA613FD1F3F6022EF276A1666DDA3BE518CB634F67B185BD2016DB2DC20E56C1C9B58CD411710E802FCFED0E3E1E182C37A9684A007EF0DEBBBCB783F37A0D39E2B6FAB147A3BCD75B1C24FA5939BDD9501D5E0365A60E58BE429C821BF3F774DC4603D43CE355412CC3DBF47639DF7B33CFEF4138133255770F2659E44F2FC9EE285FCDCEC414B473CCB31BA39BA798CDF1FF28A3EBD7549341C8E809E8AABF836C7FB59DB4025ED1DC5BF1874EDF4511ECCC397050C8C3F404FB04BF52DF4F35411EBFCFEFCB70C2AF6EE8AFC32A539F624F0E30D47DE8F9138B0C9B24F03F5CD53E05CA77D63CAA8800CA567E4D60D8D4ECBA9F9FE3C75FADED32267AB07ED635AD14CB6A87B1F8D5B5BD43F7C04E14DB30935A6B6CA780F2FBD10CD2EAE8DD13D6C9FA89334A8ADEAC40D63C54B6E881F9F382D3056BF7DACFFC6914A6DF60F64E7C5FE8EB222FD71632318CDC5E3CF8EC48602D238E95FC06C9BDBBD3D85535DED236D1FFA4EB1F3939B334A222BBF7FE034EB1599A7E20DFF89F92E9B3EE0D45FA7103A9B8BE6F727EC6D338C464AAA1B6B8AF426BA2153793FF7C43EEE7A43E6038296B83E130BAA9D467DB7A9B8E29E18B8F4E4493DB3E1BE4CDC1ABA3074A8D69058420FB2F56BCCD3CAB0806FA9C1E825D6F18644CD9137AB9195DD63A8BD3BA9F5C9BF0AEC9F5B6E605B2C02CAA93FB10A5F03ADD7370A981F3A99F0F3CC2DA93C298292E9859C01BBB088FE6CD979FC5A02127305D63C72B319EDD48A0EE6BE431C17B3F8E4FFDAC1F5D9A9F4EB7443EE2D3CAD6A3508A918C48DBB7F89081B7087C94A60F9FD297839305DA999BE163F234E3ED7D8D8CDFBA16AE5327F3E9D5925DF533EF5FEA2F26D3784CFB578877E15799DB73DAEC8D767F9FD81597235251D2DC413C2E1F58887AF75783F8248EC923F57F93D81A88D9E3E1E045997FD3C40B1BF83CEFC9CC2CCC079197928232333623BE67DA6A70B4818095DEEC23ABEC73E4DC9E1A74E04AEC1D420EB533CF3C06C242E1612F85A560A2861A0E54C218AC1834FCCDBD2F61FBC3B32983F25B29F5967A7219C74A10C769002C1869E9DC926A99C9D1AC92CC8BC3A5D151D405693BA0DBE292D94F40B918AFCEE6851DFC215B3738975F1EFAA32923037D96656C2D2B94B015CD1DA5F43D0A8FFA063099BA0BFB246724C8E61150FB2126EDE245963F4454EBCFF5105BDA267D598E2D1E9985136AF4348D8FCF96F355B27AE6E6F5378415D8A8D1CAD3EC3426969BF5790DBA0C01EF9B7E86095D9313F74309E01C7BA00B9B0E85DA89900D6F89DEA5BCA9273C017B56139F9CF13E7DB74724240262CBDFCEC05FB5DDAA64CB98257C9AAF7AA48AAD36577B3D6F11CD0A074D5B15860B2791E8E8B87AB2A5B2419F61561E6ECF56746E2185EBFFF0F96F821B38B0F0000
Thanks,
Now we've got more of the Java code, we can see the problem: you've got an extra layer of serialization around your real data. That has nothing to do with compression really.
Here's an example to show what I mean:
import java.io.*;
public class Test {
public static void main(String[] args) throws Exception {
try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
try (ObjectOutputStream oos = new ObjectOutputStream(output)) {
oos.writeObject(new byte[5]);
}
byte[] data = output.toByteArray();
System.out.println(data.length);
}
}
}
That's writing a byte array that's 10 bytes long - but the result is 32 bytes long, because of the extra "wrapper" information. Note that the extra 27 bytes is the same as the discrepancy you've seen.
Fundamentally, it's odd to wrap a byte array in this way, and if you can possibly change the original code, that would be for the best. If you absolutely can't do that, it may be safe to just ignore the first 27 bytes of the resulting data.
In SQL, I have a field called "Data" that contains what was once a PDF, but has been converted to a VARBINARY(MAX) field. I am pulling that data from a java servlet, and I need to know how to format it so that it can be sent to the front end and displayed as a PDF. I've seen a number of solutions that relate to BASE 64 encoding\decoding but those have not proven useful. Here is an example of what the data looks like after it has been put into SQL:
0x255044462D312E350D0A25B5B5B5B50D0A312030206F626A0D0A3C3C2F547970652F436174616C6F672F50616765732032203020522F4C616E6728656E2D555329203E3E0D0A656E646F626A0D0A322030206F626A0D0A3C3C2F547970652F50616765732F436F756E7420312F4B6964735B2033203020525D203E3E0D0A656E646F626A0D0A332030206F626A0D0A3C3C2F547970652F506167652F506172656E742032203020522F5265736F75726365733C3C2F466F6E743C3C2F46312035203020522F46322037203020523E3E2F50726F635365745B2F5044462F546578742F496D616765422F496D616765432F496D616765495D203E3E2F4D65646961426F785B2030203020363132203739325D202F436F6E74656E74732034203020522F47726F75703C3C2F547970652F47726F75702F532F5472616E73706172656E63792F43532F4465766963655247423E3E2F546162732F533E3E0D0A656E646F626A0D0A342030206F626A0D0A3C3C2F46696C7465722F466C6174654465636F64652F4C656E67746820323737373E3E0D0A73747265616D0D0A789C955A4B6FE4C611BE0BD07F9823279068369BCFA39D788304D985836C72117CA038DCD100323922C5C5FEFCD4ABBB8BD4702CC1C07AD88FEAEA7A7E55AD5FBEDEDEFCF4C9ECD2244EB2DDD76FB7376697C07F3062ABB8B4BB3231B1AD765FFFB8BD497647FCE7EFB7370FD1E7666CBBE7DDE77D1635E3A9DF57D1B0FF7DF7F59FB737BF02C55FBE063AB6B4715A6A3A0FD14EAD3548B54CE2BCCA764551C5F92E83AF3ADF997C3776B737DFFEC2F47EFA94EE0C2C2B165C96699CA4B011B704261FA27F0D63B73769F4C7FEBE84E3EE6D1D9DF6F75974DE1B134D33FEABA60EC3DE24D1332E18461C2AA38996BFEE7359D2F0161B75AF70E73B3FDE0EFDD4B5AF305A46B3EC6D0E482E9C47BFA6D6FFEC8F38CFFB3B38358FFC61B127FCEBFE3EA5219A6B561C7FC76F90FC8CAB26184BABE81B521A81453E04571C4F4080EEF5BC2FA206D66549D48D0D721BEE40C4981175A917244D926AF0CA22A999AF566CEB30B79B3A5C6B2DCF975A23466662E43CE3A1747287D7ABE9D043CC9CC06DFF01ECF73C43DB06DA46BBCE8E61588612ECBCF0481DA4E234DF3A4D8E3045F4050547120822D47A00F29D9F45F6C45C707C216318988643F38CE427C5B3577B2377647D1751DFA2E20EC4601F2EF3327BC39A026956DF84CB68EA71F6D6BC3074B851B08C4DF5D96D175CAB2F5B39DD791EE72926DB405BF902BF40BC62806B0B9EE609475ABCEEF9844A08CE464AE39D406262B325DE0FFC9BC65BBCB19B6D07A4D61FE73DF8D446284A2B1BD7A5E2FB41F9DB7FC8DCA733CAAEEB0F7B0918D3D4F10124B5012D2E03AEE711B80FA7F7A82E0E1981E2CF48B1EB8960431BD3B7A6BAF22F71D1E17082A1E1AAA2D2F7FB59BAF2B349794437EE8D25F3484A0821B9B211654D935C0B17FD5745C6BA006207096738A962C969B9AEEF5AB5AEFBC197A38F4D5BC0C9E0139E27E5188AAFBF2A8BF73722C203B913EB539821990F2FC8D18C1AAE2B1045DF70D035A5BBFBA4591635C1763CA039F6DE4878F44056705569C9FBBDCBACBDAB1939C99C3A48B72E2AE4C4CB409F1D04051924FD35530B3C9B9C13531A720331DA86C886669C1121F45F21B1725F5C4119A6097A4037640128D3CFD9F0FDDC0B29AB41413AF797907CE4A0D504B60F9EB40E1779F0FD623BA0AB3003C91F2E5EB8F0CB7184366DA1941C62825132DFC62879FD6EBFCBEB95DF11CBC4E1343514F193E83C905AF1D32686B9FCE172330E105870B64723A8940E5548FAE008739049AF63B2438A4F38ECDC72E9957E669D88CC92559F75254C7A8F0FA47B600366C0AD5C9A99640739F5346BFDE370D3CAFE96032B47DC82D79014C8A6953F6FE8A37CB74BE5D5CAA5D89E89B5961D9E85E620406E17C10EBF97580947484833271E1CCA520E0FC8BDC76F2E5DE30676B990BD7007C0E999A68D3E416D7AEA904B72EBC308317BA9485CD18D03305EBACFDF20483C3514BF3AEFC5FE3C2147A4B237A456E9D5E48B8480BF9EEE8288BA795337858DB3322887B4704D41C53A51CD0A369F1796CA8046A017FC730CA8077D0942F8716CBE636E23E048631036070CDAB1DFFF6FF83553C6995E280F989A719ED40FCEEF0C923863525639A1D840EF97A06308691B655251C7A656125846A0654595C6D62C963EB10F1E46E2793CBDDE81F69913C152F70A4C99F292D71BA920BAF9E8F25A136E1F6E4059BA2799D1F71DA6CB4D0BB025F22A169016B129AE1A400EEB161610144C760746BE031BEF49D97D8B4989113C5E63C45C476B89C78EB29A46E872DD3BC953DFFC1DE696EEF3E86266A6A25AC56270312D0F994D73B42A21ABE0FA1AB730DB2C55C87668790558CD869EAB32AE8D96C995AC94A64ACE7F1206D32C2E8D16B2605FE413401068FFC02E41E19F32429AFAD2EF9E73814D2F25155795C0ACC475C09A35142ECD2B0E838D2D0AEB34352AD33B67C351AD557661AF53A06E956F8535A8782F6B0443A670CC342DCD847A68A2637BB95B00F7A975F0924410B371138DFF51EA239978E53E4A0D992F4B2D5C2E3439586C682D29DFAFB5A45E69ED4D0FC0948533F7E28D4A705241F5B0F43E5378EA62E2E5D50B3DC781E827D0AF84690A2385826BF8E16AA3C26D18427B842A1C45EB33264EAE13008C4F40592648256F02305E89F478C633BA9EC604B6B474BC60D66599EE648556F3C45AA223670744715F730DC767F5FBDD2DABD7EEB6464C2EB8484594B32A9CC44451740F5F9F053B476DCC63ECE33DF5455E5DE03B7623656941E1C1AD7971C8EAD3B33F2E442E09F7CB8AEBCE27B975B558A06E76041CFBAD989699D85A2D9307CE502A2D2DB1CF02F1DBE8ACD32FC1FAD65BEB7429FF62928020DB0EFD77DCD8782CE42C417D3E4230C70CBAA9F6F2FDFE9A9517FD7599734BBA938BA939445F9F4582634A6D176AD5F262F4833B76A17AFB9B772FA8BB690F07C071E29AC08567CCF5B3F35D9635162415FC2B18C2E998E655B502A2FF41FF7B0CD05081D47959F0318D5832DF6FAE1C1D4ED2C62BB81FC2C52116860D42B7695313C5071CB0583BE0C491A4EBEF7C450F676286AAAD6EA316D2AAF5C5AE879775297517972C56F721BE28B0E7FB10CD1286B03B7A74090B24C2F9E3A4EF22B3CA51FDAFBB7024A1DBC4B5027B899FAF2750AEA340FB42A0773D0D5F87438C682621332D2C55DFC077C0D57D49994FDC70D0F65B08A4D8D461F6016FCAD6DEC4717DC42EDCE5CC75BF44A59AA849CBB8D4341F04D0868B4B129F9446D05C0CC3962C5B410686CBAD4703A102B6E9C2C70919A1178A796B5A7892C8154759AED4389942020B7D5DB75BF99F9401CEA7351CE9E86EAF813C9742F2F1F671C4BAA9037170D600F9AA56ED073CD3AE3D33B41D42FC9BB87974706D08631340ACD5C566AD377259C7F79A96D84FE63C4A3A7AB53577E1884E35DBFD568AA8846CACC188C5081397935227D74B75471F1C41A82B21C4A03F52F09F8404699E02B4499345092F97ECF8B074B572D9B9280228DA504A52C4892EC36C72B510CF4C1D57562BA6EB4F7BF134573EE9D7889DA4A1A7810B3317BC72DD6B76FDC13F2B37B2CBC5538020480432110A1B57FAD59CBDB0FADA8258DBB55612A756DF7BBBD6B2B551C2BC6EE1B6B671B6B07081B8680A3D9B41B50C1015DF74AB5369306A559AF0832B3B256103059D6D0A5194AFAEAA90D0D39A9D1E1F6EF053B270785B4288D7CCED85AC846F5A74CCD137EC5F75E0736DC0B5F3C59EF69B3C09630A5F8447B242D4398EF28899E293ED338286C1215FD8EBDD25ADDDAAD011E0B0763572D9B278BF5ECB6AA5D720D34CDAEF33414FCC0EE791DE874FEA81420273269D86C12B4CBD60FAE21356AD7AEAA486664D4A5E1D1784A936D5347D02E07A56DE0D8BCD67435CDA7A1E51552A120E72614EC4C3249F0ECBBD658A401501DA112162AA430A57EA5755547CC0F58AB5EBF9F6B23C7A71D8F1ADF5D446FD8C6FB4A1D785C33657C85D1BA2A4235CE0F16CD371C7D53DCFE0E4F2AD43910D92F1CB7CE7DF2AD88D1FFC8E05B9B896CCA80951C7B2F595110F39FCFF4821199963FFBC1C56B22CC3669312DA03B9F1F2FA5CB8A88BBFAB27B2DDBCB7D9075C2E5BBBDC5690DFF15F5648C59BEBF44DEFC726043D4074143EECC517F9CC15A3571A24FE41FB59414079167E74CD98266014F52725AD13641D7DE2268EEFA2C0E6EBBD6F772071D15213400EBDFCD710E1595AB7BCB90AB9861CACFD80C7591BE7F66D507CE3EE3B0C6CDEFA7329BEAAC5728C278B22D294820E970F2B015470F4CF9C438BDD764FD46475D01C61D30E619BC2250ED050A5AC3BC6EA918DD44EE47B92D7CBDC6D61892CADC9958234DEF6F2E9AF99D24B7FCA64F189B8BCB0EDFF5747508E0D0A656E6473747265616D0D0A656E646F626A0D0A352030206F626A0D0A3C3C2F547970652F466F6E742F537562747970652F54727565547970652F4E616D652F46312F42617365466F6E742F417269616C2C426F6C642F456E636F64696E672F57696E416E7369456E636F64696E672F466F6E7444657363726970746F722036203020522F4669727374436861722033322F4C61737443686172203131342F576964746873203130203020523E3E0D0A656E646F626A0D0A362030206F626A0D0A3C3C2F547970652F466F6E7444657363726970746F722F466F6E744E616D652F417269616C2C426F6C642F466C6167732033322F4974616C6963416E676C6520302F417363656E74203930352F44657363656E74202D3231302F436170486569676874203732382F4176675769647468203437392F4D6178576964746820323632382F466F6E74576569676874203730302F58486569676874203235302F4C656164696E672033332F5374656D562034372F466F6E7442426F785B202D363238202D3231302032303030203732385D203E3E0D0A656E646F626A0D0A372030206F626A0D0A3C3C2F547970652F466F6E742F537562747970652F54727565547970652F4E616D652F46322F42617365466F6E742F417269616C2F456E636F64696E672F57696E416E7369456E636F64696E672F466F6E7444657363726970746F722038203020522F4669727374436861722033322F4C61737443686172203132302F576964746873203131203020523E3E0D0A656E646F626A0D0A382030206F626A0D0A3C3C2F547970652F466F6E7444657363726970746F722F466F6E744E616D652F417269616C2F466C6167732033322F4974616C6963416E676C6520302F417363656E74203930352F44657363656E74202D3231302F436170486569676874203732382F4176675769647468203434312F4D6178576964746820323636352F466F6E74576569676874203430302F58486569676874203235302F4C656164696E672033332F5374656D562034342F466F6E7442426F785B202D363635202D3231302032303030203732385D203E3E0D0A656E646F626A0D0A392030206F626A0D0A3C3C2F417574686F72284D617263656C204D6172696E6F29202F43726561746F7228FEFF004D006900630072006F0073006F0066007400AE00200057006F007200640020003200300031003029202F4372656174696F6E4461746528443A32303136303730373039333831322D30342730302729202F4D6F644461746528443A32303136303730373039333831322D30342730302729202F50726F647563657228FEFF004D006900630072006F0073006F0066007400AE00200057006F007200640020003200300031003029203E3E0D0A656E646F626A0D0A31302030206F626A0D0A5B2032373820302030203020302030203020302030203020302030203020302030203020302030203020302030203020302030203020302030203020302030203020302030203020302030203020302030203020302030203020302030203833332030203020302030203020302030203020302030203020302030203020302030203020302030203535362030203535362030203535362030203020302032373820302030203237382030203631312036313120302030203338395D200D0A656E646F626A0D0A31312030206F626A0D0A5B20323738203020302030203020302030203020302030203020302032373820302032373820302030203020302030203020302030203020302030203020302030203020302030203020363637203020373232203732322036363720363131203020302032373820302030203535362038333320373232203020363637203737382030203636372030203732322036363720302030203020302030203020302030203020302035353620353536203530302035353620353536203237382035353620353536203232322030203020323232203833332035353620353536203535362035353620333333203530302032373820353536203530302030203530305D200D0A656E646F626A0D0A31322030206F626A0D0A3C3C2F547970652F585265662F53697A652031322F575B2031203420325D202F526F6F742031203020522F496E666F2039203020522F49445B3C33454531373636413535414137333435413738303236393235343731373330323E3C33454531373636413535414137333435413738303236393235343731373330323E5D202F46696C7465722F466C6174654465636F64652F4C656E6774682035353E3E0D0A73747265616D0D0A789C63600082FFFF1981A420030388F283506D608A31154CF17482295E5D30C52704A1368229FE89604AA0184C09BA3030000034DB067B0D0A656E6473747265616D0D0A656E646F626A0D0A787265660D0A302031330D0A3030303030303030303020363535333520660D0A30303030303030303137203030303030206E0D0A30303030303030303738203030303030206E0D0A30303030303030313334203030303030206E0D0A30303030303030333537203030303030206E0D0A30303030303033323039203030303030206E0D0A30303030303033333733203030303030206E0D0A30303030303033363032203030303030206E0D0A30303030303033373631203030303030206E0D0A30303030303033393835203030303030206E0D0A30303030303034323131203030303030206E0D0A30303030303034343230203030303030206E0D0A30303030303034363937203030303030206E0D0A747261696C65720D0A3C3C2F53697A652031332F526F6F742031203020522F496E666F2039203020522F49445B3C33454531373636413535414137333435413738303236393235343731373330323E3C33454531373636413535414137333435413738303236393235343731373330323E5D203E3E0D0A7374617274787265660D0A343935310D0A2525454F460D0A787265660D0A3020300D0A747261696C65720D0A3C3C2F53697A652031332F526F6F742031203020522F496E666F2039203020522F49445B3C33454531373636413535414137333435413738303236393235343731373330323E3C33454531373636413535414137333435413738303236393235343731373330323E5D202F5072657620343935312F5852656653746D20343639373E3E0D0A7374617274787265660D0A353336360D0A2525454F46
I've gotten to the point where I can display a PDF with the right number of pages, but each of those pages are completely blank. Any help would be greatly appreciated. The database says that the datatype is "application/pdf;filename="DocName.pdf";frevvo-attachment=true; charset=utf-8" and the conversion can be on Java or Javascript.
Update:
So I am able to get this to work thanks to the help of Mark, but there are some exceptions. On some I get the following error:
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 43677
at java.lang.String.charAt(String.java:658)
at pdftestapp.PDFTestApp.hexStringToByteArray(PDFTestApp.java:40)
at pdftestapp.PDFTestApp.main(PDFTestApp.java:31)
Here is my code:
package pdftestapp;
import java.io.*;
import java.util.Base64;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import java.nio.file.Files;
import java.nio.file.Paths;
/**
*
* #author mmarino
*/
public class PDFTestApp {
/**
* #param args the command line arguments
*/
public static void main(String args[]) throws Exception{
String str = "0x255044462D312E350..."; //data omitted
str = str.substring(2)
byte[] arr = hexStringToByteArray(str1);
Files.write(Paths.get("test.pdf"), arr);
}
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
}
To test it:
If you got the String representation use something like this:
import java.nio.file.Files;
import java.nio.file.Paths;
public class Main {
public static void main(String args[]) throws Exception{
String str = "255[...]0A2525454F46"; //0x removed, omitted data
byte[] arr = hexStringToByteArray(str);
Files.write(Paths.get("test.pdf"), arr);
}
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
}
Your pdf file will be able to read:
If your pdf is in a byte array you could write it directly to file.
To do it:
If the question is how to display it to an user with a browser you should do something simmilar:
#WebServlet("/foo.pdf")
public class PdfServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
byte[] file = getsomehow();
response.setHeader("Content-Type", "Your staffs content type");
response.setHeader("Content-Length", file.length);
response.setHeader("Content-Disposition", "inline; filename=\"something.pdf\"");
response.getOutputStream().write(file);
response.getOutputStream().close();
}
}
I appear to be getting corruption when reading an ObjectInputStream. The attached snippet throws an exception prior to completion. I fixed the example to call oos.writeObject( p1 ) as suggested.
The Exception stack is as follows:
java.lang.OutOfMemoryError: Java heap space
at test.POJO.readExternal(STest.java:82)
at java.io.ObjectInputStream.readExternalData(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at test.STest.test(STest.java:37)
I believe this OutOfMemoryError exception to be misleading. I added a print statement showing the readExternal(..) behavior and am seeing a large value being pulled from ObjectInputStream, this does not correlate to what was written. If DIM is set to 5 it works if set to 15 I get the above exception. If I lower the number of bytes written per array element I get more successful iterations.
package test;
import static org.junit.Assert.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import org.junit.Test;
public class STest
{
#Test
public void test() throws Exception
{
POJO p1 = new POJO();
POJO p2 = new POJO();
// Initialize and serialize POJO 1
// --------------------------------
p1.hydrate();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream( baos );
oos.writeObject( p1 );
oos.flush();
oos.close();
byte [] baSerialized = baos.toByteArray();
// Parse POJO 2
// -------------
ObjectInputStream ois = new ObjectInputStream( new ByteArrayInputStream( baSerialized ) );
p2 = (POJO)ois.readObject();
// Test Result
// ------------
byte [][] baa1 = p1._baa;
byte [][] baa2 = p2._baa;
for ( int i=0; i < baa1.length; i++ )
{
String str1 = new String( baa1[ i ] );
String str2 = new String( baa2[ i ] );
assertTrue( str1.equals( str2 ) );
}
}
}
class POJO implements Externalizable
{
protected static final int DIM = 5;
protected byte [][] _baa = null;
public POJO()
{
}
public void hydrate()
{
_baa = new byte[ DIM ][];
for ( int i = 0; i < _baa.length; i++ )
{
_baa[ i ] = ("This is a serialize and parse test, it will be interesting to see if it completes without exception, I suspect not as there appears be a bug in the JRE - " + i).getBytes();
}
}
#Override
public void readExternal( ObjectInput oi ) throws IOException, ClassNotFoundException
{
int iDim = oi.readInt();
_baa = new byte[ iDim ][];
for ( int i=0; i < iDim; i++ )
{
int iSize = oi.readInt();
System.out.println( iSize );
byte [] ba = new byte[ iSize ];
oi.read( ba );
_baa[ i ] = ba;
}
}
#Override
public void writeExternal( ObjectOutput oo ) throws IOException
{
oo.writeInt( _baa.length );
for ( int i=0; i < _baa.length; i++ )
{
oo.writeInt( _baa[ i ].length );
oo.write( _baa[ i ] );
}
}
}
p1.writeExternal(o);
That should be:
oo.writeObject(p1);
You aren't supposed to call your own writeExternal() method directly. The ObjectOutputStream does that.