Store binary sequence in byte array? - java

I need to store a couple binary sequences that are 16 bits in length into a byte array (of length 2). The one or two binary numbers don't change, so a function that does conversion might be overkill. Say for example the 16 bit binary sequence is 1111000011110001. How do I store that in a byte array of length two?

String val = "1111000011110001";
byte[] bval = new BigInteger(val, 2).toByteArray();
There are other options, but I found it best to use BigInteger class, that has conversion to byte array, for this kind of problems. I prefer if, because I can instantiate class from String, that can represent various bases like 8, 16, etc. and also output it as such.
Edit: Mondays ... :P
public static byte[] getRoger(String val) throws NumberFormatException,
NullPointerException {
byte[] result = new byte[2];
byte[] holder = new BigInteger(val, 2).toByteArray();
if (holder.length == 1) result[0] = holder[0];
else if (holder.length > 1) {
result[1] = holder[holder.length - 2];
result[0] = holder[holder.length - 1];
}
return result;
}
Example:
int bitarray = 12321;
String val = Integer.toString(bitarray, 2);
System.out.println(new StringBuilder().append(bitarray).append(':').append(val)
.append(':').append(Arrays.toString(getRoger(val))).append('\n'));

I have been disappointed with all of the solutions I have found to converting strings of bits to byte arrays and vice versa -- all have been buggy (even the BigInteger solution above), and very few are as efficient as they should be.
I realize the OP was only concerned with a bit string to an array of two bytes, which the BitInteger approach seems to work fine for. However, since this post is currently the first search result when searching "bit string to byte array java" in Google, I am going to post my general solution here for people dealing with huge strings and/or huge byte arrays.
Note that my solution below is the only solution I have ran that passes all of my test cases -- many online solutions to this relatively simple problem simply do not work.
Code
/**
* Zips (compresses) bit strings to byte arrays and unzips (decompresses)
* byte arrays to bit strings.
*
* #author ryan
*
*/
public class BitZip {
private static final byte[] BIT_MASKS = new byte[] {1, 2, 4, 8, 16, 32, 64, -128};
private static final int BITS_PER_BYTE = 8;
private static final int MAX_BIT_INDEX_IN_BYTE = BITS_PER_BYTE - 1;
/**
* Decompress the specified byte array to a string.
* <p>
* This function does not pad with zeros for any bit-string result
* with a length indivisible by 8.
*
* #param bytes The bytes to convert into a string of bits, with byte[0]
* consisting of the least significant bits in the byte array.
* #return The string of bits representing the byte array.
*/
public static final String unzip(final byte[] bytes) {
int byteCount = bytes.length;
int bitCount = byteCount * BITS_PER_BYTE;
char[] bits = new char[bitCount];
{
int bytesIndex = 0;
int iLeft = Math.max(bitCount - BITS_PER_BYTE, 0);
while (bytesIndex < byteCount) {
byte value = bytes[bytesIndex];
for (int b = MAX_BIT_INDEX_IN_BYTE; b >= 0; --b) {
bits[iLeft + b] = ((value % 2) == 0 ? '0' : '1');
value >>= 1;
}
iLeft = Math.max(iLeft - BITS_PER_BYTE, 0);
++bytesIndex;
}
}
return new String(bits).replaceFirst("^0+(?!$)", "");
}
/**
* Compresses the specified bit string to a byte array, ignoring trailing
* zeros past the most significant set bit.
*
* #param bits The string of bits (composed strictly of '0' and '1' characters)
* to convert into an array of bytes.
* #return The bits, as a byte array with byte[0] containing the least
* significant bits.
*/
public static final byte[] zip(final String bits) {
if ((bits == null) || bits.isEmpty()) {
// No observations -- return nothing.
return new byte[0];
}
char[] bitChars = bits.toCharArray();
int bitCount = bitChars.length;
int left;
for (left = 0; left < bitCount; ++left) {
// Ignore leading zeros.
if (bitChars[left] == '1') {
break;
}
}
if (bitCount == left) {
// Only '0's in the string.
return new byte[] {0};
}
int cBits = bitCount - left;
byte[] bytes = new byte[((cBits) / BITS_PER_BYTE) + (((cBits % BITS_PER_BYTE) > 0) ? 1 : 0)];
{
int iRight = bitCount - 1;
int iLeft = Math.max(bitCount - BITS_PER_BYTE, left);
int bytesIndex = 0;
byte _byte = 0;
while (bytesIndex < bytes.length) {
while (iLeft <= iRight) {
if (bitChars[iLeft] == '1') {
_byte |= BIT_MASKS[iRight - iLeft];
}
++iLeft;
}
bytes[bytesIndex++] = _byte;
iRight = Math.max(iRight - BITS_PER_BYTE, left);
iLeft = Math.max((1 + iRight) - BITS_PER_BYTE, left);
_byte = 0;
}
}
return bytes;
}
}
Performance
I was bored at work so I did some performance testing comparing against the accepted answer here for when N is large. (Pretending to ignore the fact that the BigInteger approach posted above doesn't even work properly as a general approach.)
This is running with a random bit string of size 5M and a random byte array of size 1M:
String -> byte[] -- BigInteger result: 39098ms
String -> byte[] -- BitZip result: 29ms
byte[] -> String -- Integer result: 138ms
byte[] -> String -- BitZip result: 71ms
And the code:
public static void main(String[] argv) {
int testByteLength = 1000000;
int testStringLength = 5000000;
// Independently random.
final byte[] randomBytes = new byte[testByteLength];
final String randomBitString;
{
StringBuilder sb = new StringBuilder();
Random rand = new Random();
for (int i = 0; i < testStringLength; ++i) {
int value = rand.nextInt(1 + i);
sb.append((value % 2) == 0 ? '0' : '1');
randomBytes[i % testByteLength] = (byte) value;
}
randomBitString = sb.toString();
}
byte[] resultCompress;
String resultDecompress;
{
Stopwatch s = new Stopwatch();
TimeUnit ms = TimeUnit.MILLISECONDS;
{
s.start();
{
resultCompress = compressFromBigIntegerToByteArray(randomBitString);
}
s.stop();
{
System.out.println("String -> byte[] -- BigInteger result: " + s.elapsed(ms) + "ms");
}
s.reset();
}
{
s.start();
{
resultCompress = zip(randomBitString);
}
s.stop();
{
System.out.println("String -> byte[] -- BitZip result: " + s.elapsed(ms) + "ms");
}
s.reset();
}
{
s.start();
{
resultDecompress = decompressFromIntegerParseInt(randomBytes);
}
s.stop();
{
System.out.println("byte[] -> String -- Integer result: " + s.elapsed(ms) + "ms");
}
s.reset();
}
{
s.start();
{
resultDecompress = unzip(randomBytes);
}
s.stop();
{
System.out.println("byte[] -> String -- BitZip result: " + s.elapsed(ms) + "ms");
}
s.reset();
}
}
}

Related

How to encode chars in 2-bits? in java

DNA molecules are denoted by one of four values: A, C, G, or T. I need to convert a string of characters from A, C, G, and T to an array of bytes, encoding each of the characters
with two bits.A with bits 00, C with bits 01, G with 10, and T with 11. I don't understand how to convert characters to 2 bits. I was trying to shift and mask, but got wrong result.
At the very beginning, I check if there are characters in the line. Then i convert each character into a bit value and insert it into an array. When i insert ACGT, in the output i got 0 1 3 2. And here I have a problem, because I don’t understand how to convert the value to 2 bits.
Scanner text = new Scanner(System.in);
String str = text.nextLine();
if (str.contains("A") && str.contains("C") && str.contains("G") && str.contains("T")){
System.out.println("");
}
else
{
System.out.println("wrong command format");
}
byte mas[] = str.getBytes();
System.out.println("String in byte array : " + Arrays.toString(mas));
for (int i = 0; i < mas.length; i++){
byte mask = 3;
byte number = mas[i];
byte result = (byte)((number >> 1) & mask);
System.out.println(result);
}
}
}
It seems that you want to save the bits in a byte. The following example might give some ideas.
public class Main
{
private static final int A = 0x00; // b00
private static final int C = 0x01; // b01
private static final int G = 0x02; // b10
private static final int T = 0x03; // b11
public static void main(String[] args) throws Exception
{
byte store = 0;
store = setByte(store, 0, A);
store = setByte(store, 1, C);
store = setByte(store, 2, G);
store = setByte(store, 3, T);
System.out.println(Integer.toBinaryString(store));
//11111111111111111111111111100100
System.out.println(getByte(store, 0)); //0
System.out.println(getByte(store, 1)); //1
System.out.println(getByte(store, 2)); //2
System.out.println(getByte(store, 3)); //3
}
//Behavior :: Store "value" into "store".
//Reminder :: Valid index 0 - 3. Valid value 0 - 3.
private static byte setByte(byte store, int index, int value)
{
store = (byte)(store & ~(0x3 << (2 * index)));
return store |= (value & 0x3) << (2 * index);
}
private static byte getByte(byte store, int index)
{
return (byte)((store >> (2 * index)) & 0x3);
}
}
I haven't tested this, but it may help you.
byte test = 69;
byte insert = 0b01;
byte index = 2;
final byte ones = 0b00000011;
//Clear out the data at specified index
test = (byte) (test & ~(ones << index));
//Insert data
test |= (byte) (insert << index);
It works as follows:
Clear the 2 bits at the index in the byte (using bitwise AND).
Insert the 2 data bits at the index in the byte using bitwise OR).
You can "convert" the chars ACGT to 0, 1, 2, 3 using bit arithmetic.
byte[] bytes = str.getBytes();
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte)(bytes[i] >> 1 & 3 ^ bytes[i] >> 2 & 1);
}
I suspect your initial check should be:
if (!str.matches("[ACGT]+") {
System.out.println("wrong command format");
return;
}

TEA Algorithm java implementation and the issue of 32 unsigned bits

I am trying to implement the Tiny Encryption Algorithm (TEA) in java. Since the algorithm divides each 64 bit block into left and right sub-blocks, where each sub-block is 32 unsigned integer according to this source.
As expected, I faced the issue of java not supporting unsigned 32 bit integer. I was getting errors about the number Format everywhere.
So I decided to use BigInteger, which introduced a new problem to me. Based on my understanding, since TEA uses shifting and addition of 32 bits integers, It is supposed to keep the result of these operation in 32 bits, so that the ciphertext will also be 32 bits per sub-block. However, with shifting and addition, BigInteger did not keep 32 bits per sub-block. Indeed, I got unexpectedly a very large number of bits as a ciphertext output.
So I decided to keep the BigInteger, while implementing the shift, addition, and subtraction in separate methods. Unfortunately, I am not getting correct results. As illustrated below, the decrypted ciphertext does not equal the original plaintext. What is the solution to my problem? I am getting the following output:
Original Plain Text:0x0123456789ABCDEF
CipherText:0xa0761126d09724fd
Decrypted CipherText is:0x8d5a4a234b3c6720
Below is my code.
import java.math.BigInteger;
public class TEA {
BigInteger [] K ; //128 bits key
private String plainText;
public static final BigInteger delta = new BigInteger("9e3779b9",16);
//constructor receives a string of plaintext and 128 bit key in hexadecimal
public TEA(String plainText, String key)
{
parseKey(key);
}
//constructor receives a hexadecimal
public TEA(String key)
{
parseKey(key);
}
//parses a 128 bit key, given in hexadecimal form, and store its value in 4 integers (total of 128 bits),
private void parseKey(String key)
{
if(key.substring(0,2).equals("0x"))
key= key.substring(2);
//validating input
if(key.length() != 32)
{
System.out.println("Invalid key size!");
return;
}
//dividing the key into 4 strings
String[] kStr = new String[4];
int index=-1;
for(int i=0; i<key.length(); i++)
{
if(i%8 == 0)
{
index++;
kStr[index]="";
}
kStr[index] = kStr[index] + key.charAt(i);
}
//converting the 4 hex strings into 4 integers
K= new BigInteger[4];
for(int i=0; i<4; i++)
K[i] = new BigInteger(kStr[i], 16);
}
//receives a plaintext block of 64 bits in hexadecimal to be encrypted
//returns the cipher block
String encryptBlock(String plainTextBlock)
{
if(plainTextBlock.substring(0,2).equals("0x"))
plainTextBlock= plainTextBlock.substring(2);
//validating input
if(plainTextBlock.length()!=16)
{
System.out.println("Invalid block size!");
return null;
}
//separating the string block into left and right blocks
String LStr = plainTextBlock.substring(0, 8); //left block (32 bit)
String RStr = plainTextBlock.substring(8); //right block (32 bit)
//converting left and right blocks to integers
BigInteger L = new BigInteger(LStr, 16);
BigInteger R = new BigInteger(RStr, 16);
BigInteger sum= new BigInteger("0");
//32 rounds
for(int i=0; i<32; i++)
{
sum = sum.add(delta);
L= sum(L, (sum(shiftLeft(R,4),K[0])) .xor(sum(R,sum)) .xor(sum(shiftRight(R,5),K[1]))) ;
R= sum(R, (sum(shiftLeft(L,4),K[2])) .xor(sum(L,sum)) .xor(sum(shiftRight(L,5),K[3]))) ;
//R= R.add( (shiftLeft(R,4).add(K[2])).xor(L.add(sum)).xor(shiftRight(L,5).add(K[3])) );
}
//joining back the blocks as hex
String cipherBlock = "0x"+L.toString(16)+R.toString(16)+"";
return cipherBlock;
}
//receives a ciphertext block of 64 bits in hexadecimal to be decrypted
//returns the plaintext block
String decryptBlock(String cipherBlock)
{
if(cipherBlock.substring(0,2).equals("0x"))
cipherBlock= cipherBlock.substring(2);
//validating input
if(cipherBlock.length()!=16)
{
System.out.println("Invalid block size!");
return null;
}
//separating the string block into left and right blocks
String LStr = cipherBlock.substring(0, 8); //left block (32 bit)
String RStr = cipherBlock.substring(8); //right block (32 bit)
//converting left and right blocks to integers
BigInteger L = new BigInteger(LStr, 16);
BigInteger R = new BigInteger(RStr, 16);
BigInteger sum= shiftLeft(delta,5);
//32 rounds
for(int i=0; i<32; i++)
{
R= subtract(R, (sum(shiftLeft(L,4),K[2])) .xor(sum(L,sum)) .xor(sum(shiftRight(L,5),K[3]))) ;
L= subtract(L, (sum(shiftLeft(R,4),K[0])) .xor(sum(R,sum)) .xor(sum(shiftRight(R,5),K[1]))) ;
//R= R.subtract( (L.shiftLeft(4).add(K[2])).xor(L.add(sum)).xor(L.shiftRight(5).add(K[3])) );
//L= L.subtract( (R.shiftLeft(4).add(K[0])).xor(R.add(sum)).xor(R.shiftRight(5).add(K[1])) );
sum = sum.subtract(delta);
}
//joining back the blocks as hex
String plainTextBlock = "0x"+L.toString(16)+R.toString(16)+"";
return plainTextBlock;
}
private BigInteger shiftLeft(BigInteger x, int steps)
{
BigInteger shifted=null;
boolean negative =false;
String xStr = x.toString(2);
//removing negative sign while shifting (currently)
if(xStr.charAt(0)=='-')
{
negative= true;
xStr = xStr.substring(1);
}
int additionalSize = 32- xStr.length();
for(int i=0; i<additionalSize; i++)
xStr= "0"+xStr;
for(int i=0; i<steps; i++)
{
xStr = xStr.substring(1);
xStr = xStr+"0";
}
//one last addition of negative sign if the number is negative
if(negative==true)
xStr= "-"+xStr;
//System.out.println(xStr);
shifted = new BigInteger(xStr,2);
return shifted;
}
private BigInteger shiftRight(BigInteger x, int steps)
{
BigInteger shifted=null;
boolean negative = false;
String xStr = x.toString(2);
//removing negative sign while shifting (currently)
if(xStr.charAt(0)=='-')
{
negative= true;
xStr = xStr.substring(1);
}
int additionalSize = 32- xStr.length();
for(int i=0; i<additionalSize; i++)
xStr= "0"+xStr;
for(int i=0; i<steps; i++)
{
xStr = xStr.substring(0,xStr.length()-1);
xStr = "0"+xStr;
}
//one last addition of negative sign if the number is negative
if(negative==true)
xStr= "-"+xStr;
shifted = new BigInteger(xStr,2);
return shifted;
}
private BigInteger sum(BigInteger a, BigInteger b)
{
BigInteger sum = a.add(b);
String sumStr = sum.toString(2);
if(sumStr.length()>32)
{
int diff = sumStr.length()- 32;
sumStr = sumStr.substring(diff);
}
BigInteger newSum = new BigInteger(sumStr,2);
return newSum;
}
private BigInteger subtract(BigInteger a, BigInteger b)
{
BigInteger sub = a.subtract(b);
String subStr = sub.toString(2);
if(subStr.length()>32)
{
int diff = subStr.length()- 32;
subStr = subStr.substring(diff);
}
BigInteger newSub = new BigInteger(subStr,2);
return newSub;
}
public static void main(String[] args)
{
String plainText="0x0123456789ABCDEF";
String key= "0xA56BABCD00000000FFFFFFFFABCDEF01";
TEA tea = new TEA(key);
String cipherText = tea.encryptBlock(plainText);
System.out.println("Original Plain Text:"+plainText);
System.out.println("CipherText:"+cipherText);
System.out.println("Decrypted CipherText is:"+tea.decryptBlock(cipherText));
}
}
I saw no reason to use BigIntegers, so I tried my own implementation in Java that is almost a verbatim copy of the C code in the wikipedia article. It looks correct to me, though I don't have tests to run against it.
public class TEAToy {
private final static int DELTA = 0x9e3779b9;
private final static int DECRYPT_SUM_INIT = 0xC6EF3720;
private final static long MASK32 = (1L << 32) - 1;
public static long encrypt(long in, int [] k) {
int v1 = (int) in;
int v0 = (int) (in >>> 32);
int sum = 0;
for (int i=0; i<32; i++) {
sum += DELTA;
v0 += ((v1<<4) + k[0]) ^ (v1 + sum) ^ ((v1>>>5) + k[1]);
v1 += ((v0<<4) + k[2]) ^ (v0 + sum) ^ ((v0>>>5) + k[3]);
}
return (v0 & MASK32) << 32 | (v1 & MASK32);
}
public static long decrypt(long in, int [] k) {
int v1 = (int) in;
int v0 = (int) (in >>> 32);
int sum = DECRYPT_SUM_INIT;
for (int i=0; i<32; i++) {
v1 -= ((v0<<4) + k[2]) ^ (v0 + sum) ^ ((v0>>>5) + k[3]);
v0 -= ((v1<<4) + k[0]) ^ (v1 + sum) ^ ((v1>>>5) + k[1]);
sum -= DELTA;
}
return (v0 & MASK32) << 32 | (v1 & MASK32);
}
As you can see, the fact the Java's ints are signed makes very little difference.

Java - Convert Big-Endian to Little-Endian

I have the following hex string:
00000000000008a3a41b85b8b29ad444def299fee21793cd8b9e567eab02cd81
but I want it to look like this:
81cd02ab7e569e8bcd9317e2fe99f2de44d49ab2b8851ba4a308000000000000 (Big
endian)
I think I have to reverse and swap the string, but something like this doesn't give me right result:
String hex = "00000000000008a3a41b85b8b29ad444def299fee21793cd8b9e567eab02cd81";
hex = new StringBuilder(hex).reverse().toString();
Result:
81dc20bae765e9b8dc39712eef992fed444da92b8b58b14a3a80000000000000
(wrong)
81cd02ab7e569e8bcd9317e2fe99f2de44d49ab2b8851ba4a308000000000000
(should be)
The swapping:
public static String hexSwap(String origHex) {
// make a number from the hex
BigInteger orig = new BigInteger(origHex,16);
// get the bytes to swap
byte[] origBytes = orig.toByteArray();
int i = 0;
while(origBytes[i] == 0) i++;
// swap the bytes
byte[] swapBytes = new byte[origBytes.length];
for(/**/; i < origBytes.length; i++) {
swapBytes[i] = origBytes[origBytes.length - i - 1];
}
BigInteger swap = new BigInteger(swapBytes);
return swap.toString(10);
}
hex = hexSwap(hex);
Result:
026053973026883595670517176393898043396144045912271014791797784
(wrong)
81cd02ab7e569e8bcd9317e2fe99f2de44d49ab2b8851ba4a308000000000000
(should be)
Can anyone give me a example of how to accomplish this?
Thank you a lot :)
You need to swap each pair of characters, as you're reversing the order of the bytes, not the nybbles. So something like:
public static String reverseHex(String originalHex) {
// TODO: Validation that the length is even
int lengthInBytes = originalHex.length() / 2;
char[] chars = new char[lengthInBytes * 2];
for (int index = 0; index < lengthInBytes; index++) {
int reversedIndex = lengthInBytes - 1 - index;
chars[reversedIndex * 2] = originalHex.charAt(index * 2);
chars[reversedIndex * 2 + 1] = originalHex.charAt(index * 2 + 1);
}
return new String(chars);
}

Java: convert byte[] to base36 String

I'm a bit lost. For a project, I need to convert the output of a hash-function (SHA256) - which is a byte array - to a String using base 36.
So In the end, I want to convert the (Hex-String representation of the) Hash, which is
43A718774C572BD8A25ADBEB1BFCD5C0256AE11CECF9F9C3F925D0E52BEAF89
to base36, so the example String from above would be:
3SKVHQTXPXTEINB0AT1P0G45M4KI8U0HR8PGB96DVXSTDJKI1
For the actual conversion to base36, I found some piece of code here on StackOverflow:
public static String toBase36(byte[] bytes) {
//can provide a (byte[], offset, length) method too
StringBuffer sb = new StringBuffer();
int bitsUsed = 0; //will point how many bits from the int are to be encoded
int temp = 0;
int tempBits = 0;
long swap;
int position = 0;
while((position < bytes.length) || (bitsUsed != 0)) {
swap = 0;
if(tempBits > 0) {
//there are bits left over from previous iteration
swap = temp;
bitsUsed = tempBits;
tempBits = 0;
}
//fill some bytes
while((position < bytes.length) && (bitsUsed < 36)) {
swap <<= 8;
swap |= bytes[position++];
bitsUsed += 8;
}
if(bitsUsed > 36) {
tempBits = bitsUsed - 36; //this is always 4
temp = (int)(swap & ((1 << tempBits) - 1)); //get low bits
swap >>= tempBits; //remove low bits
bitsUsed = 36;
}
sb.append(Long.toString(swap, 36));
bitsUsed = 0;
}
return sb.toString();
}
Now I'm doing this:
// this creates my hash, being a 256-bit byte array
byte[] hash = PBKDF2.deriveKey(key.getBytes(), salt.getBytes(), 2, 256);
System.out.println(hash.length); // outputs "256"
System.out.println(toBase36(hash)); // outputs total crap
the "total crap" is something like
-7-14-8-1q-5se81u0e-3-2v-24obre-73664-7-5-5cor1o9s-6h-4k6hr-5-4-rt2z0-30-8-2u-8-onz-4a2j-6-8-18-8trzza3-3-2x-6-4153to-4e3l01me-6-azz-2-k-4ckq-nav-gu-irqpxx-el-1j-6-rmf8hs-1bb5ax-3z25u-2-2r-t5-22-6-6w1v-1p
so it's not even close to what I want. I tried to find a solution now, but it seems I'm a bit lost here. How do I get the base36-encoded String representation of the Hash that I need?
Try using BigInteger:
String hash = "43A718774C572BD8A25ADBEB1BFCD5C0256AE11CECF9F9C3F925D0E52BEAF89";
//use a radix of 16, default would be 10
String base36 = new BigInteger( hash, 16 ).toString( 36 ).toUpperCase();
This might work:
BigInteger big = new BigInteger(your_byte_array_to_hex_string, 16);
big.toString(36);

How to create a UUID or GUID in Java 1.4

I need to create a UUID or GUID in java 1.4. I get a classnotfound exception when i use: java.util.UUID.
There are similar questions here linked below, but none answer with a generator for Java 1.4:
Likelihood of collision using most significant bits of a UUID in Java
Create a GUID in Java
I have also found a few classes online:
http://johannburkard.de/software/uuid/
http://jackrabbit.apache.org/api/1.4/org/apache/jackrabbit/uuid/UUID.html
What would you suggest I use to create a UUID or GUID in java 1.4?
I suppose there is no chance convincing the client to get off an unsupported version of Java? Which if the answer is no then your only recourse is to use/modify one of the open source implementations from the web. You mentioned two of them in your question, another one you might want to look at is JUG.
And oh yea, your reference to java.util.UUID failed because it's only available in Java 5 and up.
Good luck!
java.util.UUID was added to JDK since 1.5.
For a simple lightweight implementation, take a look at this blog post: http://lzkyo.iteye.com/blog/453120.
Apache Commons ID (sandbox project, so you have to build from source, but I've used it and it works): project page, svn repo
You can also check try this project but I haven't used it.
Use the TechKey functionality within SAP ISA. that is what it is there for. Also it is compatiable with the ABAP Tables and well as any Portal and SAP J2EE Tables.
Unfortunately the UUID class is available since 1.5. I just implemented this utility class that creates UUIDs as String. Fell free to use and share. I hope it helps someone else!
package your.package.name;
import java.security.SecureRandom;
import java.util.Random;
/**
* Utility class that creates random-based UUIDs as Strings.
*
*/
public abstract class RandomUuidStringCreator {
private static final int RANDOM_VERSION = 4;
/**
* Returns a random-based UUID as String.
*
* It uses a thread local {#link SecureRandom}.
*
* #return a random-based UUID string
*/
public static String getRandomUuid() {
return getRandomUuid(SecureRandomLazyHolder.SECURE_RANDOM);
}
/**
* Returns a random-based UUID String.
*
* It uses any instance of {#link Random}.
*
* #return a random-based UUID string
*/
public static String getRandomUuid(Random random) {
long msb = 0;
long lsb = 0;
// (3) set all bit randomly
if (random instanceof SecureRandom) {
// Faster for instances of SecureRandom
final byte[] bytes = new byte[16];
random.nextBytes(bytes);
msb = toNumber(bytes, 0, 8); // first 8 bytes for MSB
lsb = toNumber(bytes, 8, 16); // last 8 bytes for LSB
} else {
msb = random.nextLong(); // first 8 bytes for MSB
lsb = random.nextLong(); // last 8 bytes for LSB
}
// Apply version and variant bits (required for RFC-4122 compliance)
msb = (msb & 0xffffffffffff0fffL) | (RANDOM_VERSION & 0x0f) << 12; // apply version bits
lsb = (lsb & 0x3fffffffffffffffL) | 0x8000000000000000L; // apply variant bits
// Convert MSB and LSB to hexadecimal
String msbHex = zerofill(Long.toHexString(msb), 16);
String lsbHex = zerofill(Long.toHexString(lsb), 16);
// Return the UUID
return format(msbHex + lsbHex);
}
private static long toNumber(final byte[] bytes, final int start, final int length) {
long result = 0;
for (int i = start; i < length; i++) {
result = (result << 8) | (bytes[i] & 0xff);
}
return result;
}
private static String zerofill(String string, int length) {
return new String(lpad(string.toCharArray(), length, '0'));
}
private static char[] lpad(char[] chars, int length, char fill) {
int delta = 0;
int limit = 0;
if (length > chars.length) {
delta = length - chars.length;
limit = length;
} else {
delta = 0;
limit = chars.length;
}
char[] output = new char[chars.length + delta];
for (int i = 0; i < limit; i++) {
if (i < delta) {
output[i] = fill;
} else {
output[i] = chars[i - delta];
}
}
return output;
}
private static String format(String string) {
char[] input = string.toCharArray();
char[] output = new char[36];
System.arraycopy(input, 0, output, 0, 8);
System.arraycopy(input, 8, output, 9, 4);
System.arraycopy(input, 12, output, 14, 4);
System.arraycopy(input, 16, output, 19, 4);
System.arraycopy(input, 20, output, 24, 12);
output[8] = '-';
output[13] = '-';
output[18] = '-';
output[23] = '-';
return new String(output);
}
// Holds lazy secure random
private static class SecureRandomLazyHolder {
static final Random SECURE_RANDOM = new SecureRandom();
}
/**
* For tests!
*/
public static void main(String[] args) {
System.out.println("// Using thread local `java.security.SecureRandom` (DEFAULT)");
System.out.println("RandomUuidCreator.getRandomUuid()");
System.out.println();
for (int i = 0; i < 5; i++) {
System.out.println(RandomUuidStringCreator.getRandomUuid());
}
System.out.println();
System.out.println("// Using `java.util.Random` (FASTER)");
System.out.println("RandomUuidCreator.getRandomUuid(new Random())");
System.out.println();
Random random = new Random();
for (int i = 0; i < 5; i++) {
System.out.println(RandomUuidStringCreator.getRandomUuid(random));
}
}
}
This is the output:
// Using `java.security.SecureRandom` (DEFAULT)
RandomUuidStringCreator.getRandomUuid()
'c4d1b0ec-c03a-4430-b210-bd692456d8f4'
'ddad65fb-aef9-4309-842d-284cef70e5f6'
'8b37cd8c-7390-4683-abed-524f97626995'
'd84b19bd-1fdb-4d76-ab7a-a845939c6934'
'ddb48e15-9512-4802-ace9-724d766643c6'
// Using `java.util.Random` (FASTER)
RandomUuidStringCreator.getRandomUuid(new Random())
'fa0a4861-6fa0-4258-8c8d-c89db9730b3e'
'bfe794fa-fe34-4ec3-aa93-5ec2e0897150'
'4c6441d8-10b5-4d8e-8dcf-6f1889d675e1'
'6f3012b7-e846-4173-8ffc-3a6e41893ea7'
'b73125a8-60f1-4dfd-b9fe-1a27aeb133a8'

Categories

Resources