1 /*
2 * Copyright 2014 - 2020 Rafael Winterhalter
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package net.bytebuddy.utility;
17
18 import java.util.Random;
19
20 /**
21 * A provider of randomized {@link java.lang.String} values.
22 */
23 public class RandomString {
24
25 /**
26 * The default length of a randomized {@link java.lang.String}.
27 */
28 public static final int DEFAULT_LENGTH = 8;
29
30 /**
31 * The symbols which are used to create a random {@link java.lang.String}.
32 */
33 private static final char[] SYMBOL;
34
35 /**
36 * The amount of bits to extract out of an integer for each key generated.
37 */
38 private static final int KEY_BITS;
39
40 /*
41 * Creates the symbol array.
42 */
43 static {
44 StringBuilder symbol = new StringBuilder();
45 for (char character = '0'; character <= '9'; character++) {
46 symbol.append(character);
47 }
48 for (char character = 'a'; character <= 'z'; character++) {
49 symbol.append(character);
50 }
51 for (char character = 'A'; character <= 'Z'; character++) {
52 symbol.append(character);
53 }
54 SYMBOL = symbol.toString().toCharArray();
55 int bits = Integer.SIZE - Integer.numberOfLeadingZeros(SYMBOL.length);
56 KEY_BITS = bits - (Integer.bitCount(SYMBOL.length) == bits ? 0 : 1);
57 }
58
59 /**
60 * A provider of random values.
61 */
62 private final Random random;
63
64 /**
65 * The length of the random strings that are created by this instance.
66 */
67 private final int length;
68
69 /**
70 * Creates a random {@link java.lang.String} provider where each {@link java.lang.String} is of
71 * {@link net.bytebuddy.utility.RandomString#DEFAULT_LENGTH} length.
72 */
73 public RandomString() {
74 this(DEFAULT_LENGTH);
75 }
76
77 /**
78 * Creates a random {@link java.lang.String} provider where each value is of the given length.
79 *
80 * @param length The length of the random {@link String}.
81 */
82 public RandomString(int length) {
83 if (length <= 0) {
84 throw new IllegalArgumentException("A random string's length cannot be zero or negative");
85 }
86 this.length = length;
87 random = new Random();
88 }
89
90 /**
91 * Creates a random {@link java.lang.String} of {@link net.bytebuddy.utility.RandomString#DEFAULT_LENGTH} length.
92 *
93 * @return A random {@link java.lang.String}.
94 */
95 public static String make() {
96 return make(DEFAULT_LENGTH);
97 }
98
99 /**
100 * Creates a random {@link java.lang.String} of the given {@code length}.
101 *
102 * @param length The length of the random {@link String}.
103 * @return A random {@link java.lang.String}.
104 */
105 public static String make(int length) {
106 return new RandomString(length).nextString();
107 }
108
109 /**
110 * Represents an integer value as a string hash. This string is not technically random but generates a fixed character
111 * sequence based on the hash provided.
112 *
113 * @param value The value to represent as a string.
114 * @return A string representing the supplied value as a string.
115 */
116 public static String hashOf(int value) {
117 char[] buffer = new char[(Integer.SIZE / KEY_BITS) + ((Integer.SIZE % KEY_BITS) == 0 ? 0 : 1)];
118 for (int index = 0; index < buffer.length; index++) {
119 buffer[index] = SYMBOL[(value >>> index * KEY_BITS) & (-1 >>> (Integer.SIZE - KEY_BITS))];
120 }
121 return new String(buffer);
122 }
123
124 /**
125 * Creates a new random {@link java.lang.String}.
126 *
127 * @return A random {@link java.lang.String} of the given length for this instance.
128 */
129 public String nextString() {
130 char[] buffer = new char[length];
131 for (int index = 0; index < length; index++) {
132 buffer[index] = SYMBOL[random.nextInt(SYMBOL.length)];
133 }
134 return new String(buffer);
135 }
136 }
137