add NanoId

This commit is contained in:
Looly 2021-07-12 20:22:30 +08:00
parent 6ebd912062
commit f9b29c5f2a
26 changed files with 294 additions and 307 deletions

View File

@ -8,6 +8,7 @@
### 🐣新特性 ### 🐣新特性
* 【core 】 DateUtil增加ceiling重载可选是否归零毫秒 * 【core 】 DateUtil增加ceiling重载可选是否归零毫秒
* 【core 】 IterUtil增加firstMatch方法 * 【core 】 IterUtil增加firstMatch方法
* 【core 】 增加NanoId
### 🐞Bug修复 ### 🐞Bug修复
* 【core 】 修复FileUtil.normalize处理上级路径的问题issue#I3YPEH@Gitee * 【core 】 修复FileUtil.normalize处理上级路径的问题issue#I3YPEH@Gitee

View File

@ -1,5 +1,7 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging> <packaging>jar</packaging>

View File

@ -1,5 +1,7 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging> <packaging>pom</packaging>

View File

@ -1,5 +1,7 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging> <packaging>jar</packaging>

View File

@ -1,5 +1,7 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging> <packaging>jar</packaging>

View File

@ -1,104 +0,0 @@
package cn.hutool.core.lang;
import java.security.SecureRandom;
import java.util.Random;
/**
* A class for generating unique String IDs.
*
* The implementations of the core logic in this class are based on NanoId, a JavaScript
* library by Andrey Sitnik released under the MIT license. (https://github.com/ai/nanoid)
*
* @author David Klebanoff
*/
public final class NanoId {
/**
* <code>NanoIdUtils</code> instances should NOT be constructed in standard programming.
* Instead, the class should be used as <code>NanoIdUtils.randomNanoId();</code>.
*/
private NanoId() {
//Do Nothing
}
/**
* The default random number generator used by this class.
* Creates cryptographically strong NanoId Strings.
*/
public static final SecureRandom DEFAULT_NUMBER_GENERATOR = new SecureRandom();
/**
* The default alphabet used by this class.
* Creates url-friendly NanoId Strings using 64 unique symbols.
*/
public static final char[] DEFAULT_ALPHABET =
"_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
/**
* The default size used by this class.
* Creates NanoId Strings with slightly more unique values than UUID v4.
*/
public static final int DEFAULT_SIZE = 21;
/**
* Static factory to retrieve a url-friendly, pseudo randomly generated, NanoId String.
*
* The generated NanoId String will have 21 symbols.
*
* The NanoId String is generated using a cryptographically strong pseudo random number
* generator.
*
* @return A randomly generated NanoId String.
*/
public static String randomNanoId() {
return randomNanoId(DEFAULT_NUMBER_GENERATOR, DEFAULT_ALPHABET, DEFAULT_SIZE);
}
/**
* Static factory to retrieve a NanoId String.
*
* The string is generated using the given random number generator.
*
* @param random The random number generator.
* @param alphabet The symbols used in the NanoId String.
* @param size The number of symbols in the NanoId String.
* @return A randomly generated NanoId String.
*/
public static String randomNanoId(final Random random, final char[] alphabet, final int size) {
if (random == null) {
throw new IllegalArgumentException("random cannot be null.");
}
if (alphabet == null) {
throw new IllegalArgumentException("alphabet cannot be null.");
}
if (alphabet.length == 0 || alphabet.length >= 256) {
throw new IllegalArgumentException("alphabet must contain between 1 and 255 symbols.");
}
if (size <= 0) {
throw new IllegalArgumentException("size must be greater than zero.");
}
final int mask = (2 << (int) Math.floor(Math.log(alphabet.length - 1) / Math.log(2))) - 1;
final int step = (int) Math.ceil(1.6 * mask * size / alphabet.length);
final StringBuilder idBuilder = new StringBuilder();
while (true) {
final byte[] bytes = new byte[step];
random.nextBytes(bytes);
for (int i = 0; i < step; i++) {
final int alphabetIndex = bytes[i] & mask;
if (alphabetIndex < alphabet.length) {
idBuilder.append(alphabet[alphabetIndex]);
if (idBuilder.length() == size) {
return idBuilder.toString();
}
}
}
}
}
}

View File

@ -0,0 +1,103 @@
package cn.hutool.core.lang.id;
import cn.hutool.core.util.RandomUtil;
import java.security.SecureRandom;
import java.util.Random;
/**
* NanoId一个小型安全 URL友好的唯一字符串 ID 生成器特点
*
* <ul>
* <li>安全它使用加密强大的随机 API并保证符号的正确分配</li>
* <li>体积小只有 258 bytes 大小压缩后无依赖</li>
* <li>紧凑它使用比 UUID (A-Za-z0-9_~)更多的符号</li>
* </ul>
*
* <p>
* 此实现的逻辑基于JavaScript的NanoId实现https://github.com/ai/nanoid
*
* @author David Klebanoff
*/
public class NanoId {
/**
* 默认随机数生成器使用{@link SecureRandom}确保健壮性
*/
private static final SecureRandom DEFAULT_NUMBER_GENERATOR = RandomUtil.getSecureRandom();
/**
* 默认随机字母表使用URL安全的Base64字符
*/
private static final char[] DEFAULT_ALPHABET =
"_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
/**
* 默认长度
*/
public static final int DEFAULT_SIZE = 21;
/**
* 生成伪随机的NanoId字符串长度为默认的{@link #DEFAULT_SIZE}使用密码安全的伪随机生成器
*
* @return 伪随机的NanoId字符串
*/
public static String randomNanoId() {
return randomNanoId(DEFAULT_SIZE);
}
/**
* 生成伪随机的NanoId字符串
*
* @param size ID长度
* @return 伪随机的NanoId字符串
*/
public static String randomNanoId(int size) {
return randomNanoId(null, null, size);
}
/**
* 生成伪随机的NanoId字符串
*
* @param random 随机数生成器
* @param alphabet 随机字母表
* @param size ID长度
* @return 伪随机的NanoId字符串
*/
public static String randomNanoId(Random random, char[] alphabet, int size) {
if (random == null) {
random = DEFAULT_NUMBER_GENERATOR;
}
if (alphabet == null) {
alphabet = DEFAULT_ALPHABET;
}
if (alphabet.length == 0 || alphabet.length >= 256) {
throw new IllegalArgumentException("Alphabet must contain between 1 and 255 symbols.");
}
if (size <= 0) {
throw new IllegalArgumentException("Size must be greater than zero.");
}
final int mask = (2 << (int) Math.floor(Math.log(alphabet.length - 1) / Math.log(2))) - 1;
final int step = (int) Math.ceil(1.6 * mask * size / alphabet.length);
final StringBuilder idBuilder = new StringBuilder();
while (true) {
final byte[] bytes = new byte[step];
random.nextBytes(bytes);
for (int i = 0; i < step; i++) {
final int alphabetIndex = bytes[i] & mask;
if (alphabetIndex < alphabet.length) {
idBuilder.append(alphabet[alphabetIndex]);
if (idBuilder.length() == size) {
return idBuilder.toString();
}
}
}
}
}
}

View File

@ -0,0 +1,7 @@
/**
* 提供各种ID生成
*
* @author looly
* @since 5.7.5
*/
package cn.hutool.core.lang.id;

View File

@ -1,14 +1,13 @@
package cn.hutool.core.util; package cn.hutool.core.util;
import cn.hutool.core.exceptions.UtilException; import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.lang.*; import cn.hutool.core.lang.ObjectId;
import cn.hutool.core.lang.Singleton;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.lang.id.NanoId;
import cn.hutool.core.net.NetUtil; import cn.hutool.core.net.NetUtil;
import java.util.Random;
import static cn.hutool.core.lang.NanoId.DEFAULT_ALPHABET;
import static cn.hutool.core.lang.NanoId.DEFAULT_NUMBER_GENERATOR;
/** /**
* ID生成器工具类此工具类中主要封装 * ID生成器工具类此工具类中主要封装
* *
@ -241,24 +240,26 @@ public class IdUtil {
*/ */
return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1); return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
} }
// ------------------------------------------------------------------- NanoId // ------------------------------------------------------------------- NanoId
/** /**
* 获取随机NanoId * 获取随机NanoId
* *
* @return 随机NanoId * @return 随机NanoId
* @since 5.7.5
*/ */
public static String randomNanoId() { public static String nanoId() {
return NanoId.randomNanoId(); return NanoId.randomNanoId();
} }
/** /**
* Static factory to retrieve a NanoId String. * 获取随机NanoId
* *
* The string is generated using the given random number generator. * @param size ID中的字符数量
* * @return 随机NanoId
* @param size The number of symbols in the NanoId String. * @since 5.7.5
* @return A randomly generated NanoId String.
*/ */
public static String randomNanoId(final int size){ public static String nanoId(int size){
return NanoId.randomNanoId(DEFAULT_NUMBER_GENERATOR, DEFAULT_ALPHABET, size); return NanoId.randomNanoId(size);
} }
} }

View File

@ -1,12 +1,9 @@
package cn.hutool.core.lang; package cn.hutool.core.lang;
import org.hamcrest.MatcherAssert; import cn.hutool.core.lang.id.NanoId;
import org.hamcrest.Matchers; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.junit.experimental.results.ResultMatchers;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@ -20,31 +17,15 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
/** /**
* Tests for NanoIdUtils. * Tests for NanoId.
* *
* @author David Klebanoff * @author David Klebanoff, Looly
* @see NanoId * @see NanoId
*/ */
public class NanoIdTest { public class NanoIdTest {
@Test @Test
public void NanoId_VerifyClassIsFinal_Verified() { public void nanoIdVerify100KRandomNanoIdsAreUniqueVerifiedTest() {
if ((NanoId.class.getModifiers() & Modifier.FINAL) != Modifier.FINAL) {
fail("The class is not final");
}
}
@Test
public void NanoId_VerifyConstructorsArePrivate_Verified() {
for (final Constructor<?> constructor : NanoId.class.getConstructors()) {
if ((constructor.getModifiers() & Modifier.PRIVATE) != Modifier.PRIVATE) {
fail("The class has a non-private constructor.");
}
}
}
@Test
public void NanoId_Verify100KRandomNanoIdsAreUnique_Verified() {
//It's not much, but it's a good sanity check I guess. //It's not much, but it's a good sanity check I guess.
final int idCount = 100000; final int idCount = 100000;
@ -62,7 +43,7 @@ public class NanoIdTest {
} }
@Test @Test
public void NanoId_SeededRandom_Success() { public void nanoIdSeededRandomSuccessTest() {
//With a seed provided, we can know which IDs to expect, and subsequently verify that the //With a seed provided, we can know which IDs to expect, and subsequently verify that the
// provided random number generator is being used as expected. // provided random number generator is being used as expected.
@ -73,8 +54,8 @@ public class NanoIdTest {
final int size = 21; final int size = 21;
final String[] expectedIds = new String[] {"kutqLNv1wDmIS56EcT3j7", "U497UttnWzKWWRPMHpLD7", final String[] expectedIds = new String[]{"kutqLNv1wDmIS56EcT3j7", "U497UttnWzKWWRPMHpLD7",
"7nj2dWW1gjKLtgfzeI8eC", "I6BXYvyjszq6xV7L9k2A9", "uIolcQEyyQIcn3iM6Odoa" }; "7nj2dWW1gjKLtgfzeI8eC", "I6BXYvyjszq6xV7L9k2A9", "uIolcQEyyQIcn3iM6Odoa"};
for (final String expectedId : expectedIds) { for (final String expectedId : expectedIds) {
final String generatedId = NanoId.randomNanoId(random, alphabet, size); final String generatedId = NanoId.randomNanoId(random, alphabet, size);
@ -84,7 +65,7 @@ public class NanoIdTest {
} }
@Test @Test
public void NanoId_VariousAlphabets_Success() { public void nanoIdVariousAlphabetsSuccessTest() {
//Test ID generation with various alphabets consisting of 1 to 255 unique symbols. //Test ID generation with various alphabets consisting of 1 to 255 unique symbols.
for (int symbols = 1; symbols <= 255; symbols++) { for (int symbols = 1; symbols <= 255; symbols++) {
@ -95,8 +76,7 @@ public class NanoIdTest {
} }
final String id = NanoId final String id = NanoId
.randomNanoId(NanoId.DEFAULT_NUMBER_GENERATOR, alphabet, .randomNanoId(null, alphabet, NanoId.DEFAULT_SIZE);
NanoId.DEFAULT_SIZE);
//Create a regex pattern that only matches to the characters in the alphabet //Create a regex pattern that only matches to the characters in the alphabet
final StringBuilder patternBuilder = new StringBuilder(); final StringBuilder patternBuilder = new StringBuilder();
@ -112,13 +92,12 @@ public class NanoIdTest {
} }
@Test @Test
public void NanoId_VariousSizes_Success() { public void nanoIdVariousSizesSuccessTest() {
//Test ID generation with all sizes between 1 and 1,000. //Test ID generation with all sizes between 1 and 1,000.
for (int size = 1; size <= 1000; size++) { for (int size = 1; size <= 1000; size++) {
final String id = NanoId.randomNanoId(NanoId.DEFAULT_NUMBER_GENERATOR, final String id = NanoId.randomNanoId(size);
NanoId.DEFAULT_ALPHABET, size);
assertEquals(size, id.length()); assertEquals(size, id.length());
} }
@ -126,7 +105,7 @@ public class NanoIdTest {
} }
@Test @Test
public void NanoId_WellDistributed_Success() { public void nanoIdWellDistributedSuccess() {
//Test if symbols in the generated IDs are well distributed. //Test if symbols in the generated IDs are well distributed.
@ -139,7 +118,7 @@ public class NanoIdTest {
for (int i = 0; i < idCount; i++) { for (int i = 0; i < idCount; i++) {
final String id = NanoId final String id = NanoId
.randomNanoId(NanoId.DEFAULT_NUMBER_GENERATOR, alphabet, idSize); .randomNanoId(null, alphabet, idSize);
for (int j = 0; j < id.length(); j++) { for (int j = 0; j < id.length(); j++) {
final String value = String.valueOf(id.charAt(j)); final String value = String.valueOf(id.charAt(j));
@ -156,28 +135,18 @@ public class NanoIdTest {
//Verify the distribution of characters is pretty even //Verify the distribution of characters is pretty even
for (final Long charCount : charCounts.values()) { for (final Long charCount : charCounts.values()) {
final double distribution = (charCount * alphabet.length / (double) (idCount * idSize)); final double distribution = (charCount * alphabet.length / (double) (idCount * idSize));
MatcherAssert.assertThat(distribution, Matchers.closeTo(1.0, 0.05)); Assert.assertTrue(distribution >= 0.95 && distribution <= 1.05);
} }
} }
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void randomNanoId_NullRandom_ExceptionThrown() { public void randomNanoIdEmptyAlphabetExceptionThrownTest() {
NanoId.randomNanoId(null, new char[] {'a', 'b', 'c'}, 10); NanoId.randomNanoId(new SecureRandom(), new char[]{}, 10);
} }
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void randomNanoId_NullAlphabet_ExceptionThrown() { public void randomNanoId256AlphabetExceptionThrownTest() {
NanoId.randomNanoId(new SecureRandom(), null, 10);
}
@Test(expected = IllegalArgumentException.class)
public void randomNanoId_EmptyAlphabet_ExceptionThrown() {
NanoId.randomNanoId(new SecureRandom(), new char[] {}, 10);
}
@Test(expected = IllegalArgumentException.class)
public void randomNanoId_256Alphabet_ExceptionThrown() {
//The alphabet is composed of 256 unique characters //The alphabet is composed of 256 unique characters
final char[] largeAlphabet = new char[256]; final char[] largeAlphabet = new char[256];
@ -190,12 +159,12 @@ public class NanoIdTest {
} }
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void randomNanoId_NegativeSize_ExceptionThrown() { public void randomNanoIdNegativeSizeExceptionThrown() {
NanoId.randomNanoId(new SecureRandom(), new char[] {'a', 'b', 'c'}, -10); NanoId.randomNanoId(new SecureRandom(), new char[]{'a', 'b', 'c'}, -10);
} }
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void randomNanoId_ZeroSize_ExceptionThrown() { public void randomNanoIdZeroSizeExceptionThrown() {
NanoId.randomNanoId(new SecureRandom(), new char[] {'a', 'b', 'c'}, 0); NanoId.randomNanoId(new SecureRandom(), new char[]{'a', 'b', 'c'}, 0);
} }
} }

View File

@ -1,5 +1,7 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging> <packaging>jar</packaging>

View File

@ -1,5 +1,7 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging> <packaging>jar</packaging>

View File

@ -1,5 +1,7 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging> <packaging>jar</packaging>

View File

@ -1,5 +1,6 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -1,5 +1,6 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -55,12 +55,6 @@
<version>${junit.version}</version> <version>${junit.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>java-hamcrest</artifactId>
<version>2.0.0.0</version>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>