diff --git a/.github/workflows/maven-build.yml b/.github/workflows/maven-build.yml index e6edb1a1f..0bbaba8d5 100644 --- a/.github/workflows/maven-build.yml +++ b/.github/workflows/maven-build.yml @@ -22,21 +22,21 @@ jobs: java: [ '8', '11' , '17' , '21' , '25' ] steps: - name: Checkout Source - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup JDK ${{ matrix.Java }} - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: 'temurin' java-version: ${{ matrix.java }} - cache: maven - name: Build with Maven - run: mvn + run: ./mvnw --batch-mode --update-snapshots --file pom.xml -Drevision=0.0.1-SNAPSHOT + -Dsurefire.useSystemClassLoader=false test --activate-profiles test,coverage diff --git a/.github/workflows/maven-publish.yml b/.github/workflows/maven-publish.yml index 6d40bcd43..61db0dc6d 100644 --- a/.github/workflows/maven-publish.yml +++ b/.github/workflows/maven-publish.yml @@ -24,10 +24,10 @@ jobs: if: ${{ inputs.revision }} steps: - name: Checkout Source - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup Maven Central Repository - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: java-version: '11' distribution: 'temurin' diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar deleted file mode 100755 index bf82ff01c..000000000 Binary files a/.mvn/wrapper/maven-wrapper.jar and /dev/null differ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index d83cf1363..423c23e5e 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -1,16 +1,3 @@ -# Copyright 2013-2023 the original author or authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.0/apache-maven-3.9.0-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar \ No newline at end of file +wrapperVersion=3.3.4 +distributionType=only-script +distributionUrl=https://maven.aliyun.com/repository/public/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip diff --git a/microsphere-annotation-processor/pom.xml b/microsphere-annotation-processor/pom.xml index 0af57d196..26473f3d3 100644 --- a/microsphere-annotation-processor/pom.xml +++ b/microsphere-annotation-processor/pom.xml @@ -18,11 +18,6 @@ Microsphere :: Java :: Annotation Processor Microsphere Annotation Processor - - 2.1 - 2.3.1 - - @@ -32,6 +27,13 @@ ${revision} + + + io.github.microsphere-projects + microsphere-lang-model + ${revision} + + org.junit.jupiter @@ -45,6 +47,22 @@ test + + + io.github.microsphere-projects + microsphere-jdk-tools + ${revision} + test + + + + + io.github.microsphere-projects + microsphere-java-test + ${revision} + test + + ch.qos.logback @@ -56,7 +74,6 @@ javax.ws.rs javax.ws.rs-api - ${javax.ws.rs.version} test @@ -64,7 +81,6 @@ javax.xml.ws jaxws-api - ${jaxws-api.version} test diff --git a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/ConfigurationPropertyAnnotationProcessor.java b/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/ConfigurationPropertyAnnotationProcessor.java index 547c702a2..4523a1e42 100644 --- a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/ConfigurationPropertyAnnotationProcessor.java +++ b/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/ConfigurationPropertyAnnotationProcessor.java @@ -18,7 +18,7 @@ package io.microsphere.annotation.processor; import io.microsphere.annotation.ConfigurationProperty; -import io.microsphere.annotation.processor.model.util.ConfigurationPropertyJSONElementVisitor; +import io.microsphere.constants.ResourceConstants; import io.microsphere.json.JSONArray; import io.microsphere.metadata.ConfigurationPropertyGenerator; @@ -35,12 +35,12 @@ import java.util.List; import java.util.Set; -import static io.microsphere.annotation.processor.model.util.ConfigurationPropertyJSONElementVisitor.CONFIGURATION_PROPERTY_ANNOTATION_CLASS_NAME; -import static io.microsphere.annotation.processor.util.MessagerUtils.printNote; +import static io.microsphere.annotation.processor.ConfigurationPropertyJSONElementVisitor.CONFIGURATION_PROPERTY_ANNOTATION_CLASS_NAME; import static io.microsphere.constants.ResourceConstants.CONFIGURATION_PROPERTY_METADATA_RESOURCE; import static io.microsphere.constants.SymbolConstants.COMMA_CHAR; import static io.microsphere.constants.SymbolConstants.LEFT_SQUARE_BRACKET_CHAR; import static io.microsphere.constants.SymbolConstants.RIGHT_SQUARE_BRACKET_CHAR; +import static io.microsphere.lang.model.util.MessagerUtils.printNote; import static io.microsphere.metadata.ConfigurationPropertyLoader.loadAll; import static javax.lang.model.SourceVersion.latestSupported; import static javax.tools.StandardLocation.CLASS_OUTPUT; @@ -62,7 +62,7 @@ * *
  • {@link #resolveMetadata(RoundEnvironment)} traverses all root elements to extract configuration property metadata.
  • *
  • {@link #writeMetadata()} writes the generated metadata into a JSON file under - * {@value #CONFIGURATION_PROPERTY_METADATA_RESOURCE_NAME} using a writer.
  • + * {@value ResourceConstants#CONFIGURATION_PROPERTY_METADATA_RESOURCE} using a writer. * * * @author Mercy @@ -106,24 +106,28 @@ public boolean process(Set annotations, RoundEnvironment private void resolveMetadata(RoundEnvironment roundEnv) { Set elements = roundEnv.getRootElements(); - if (!elements.isEmpty()) { + resolveMetadata(elements); + } + + void resolveMetadata(Set elements) { + jsonBuilder.append(LEFT_SQUARE_BRACKET_CHAR); + // Resolve the content + if (!elements.isEmpty()) { Iterator iterator = elements.iterator(); - jsonBuilder.append(LEFT_SQUARE_BRACKET_CHAR); while (iterator.hasNext()) { Element element = iterator.next(); element.accept(jsonElementVisitor, jsonBuilder); } - // append the JSON content generated by ConfigurationPropertyGenerator SPI appendGeneratedConfigurationPropertyJSON(jsonBuilder); + } - int lastIndex = jsonBuilder.length() - 1; - if (COMMA_CHAR == jsonBuilder.charAt(lastIndex)) { - jsonBuilder.setCharAt(lastIndex, RIGHT_SQUARE_BRACKET_CHAR); - } else { - jsonBuilder.append(RIGHT_SQUARE_BRACKET_CHAR); - } + int lastIndex = jsonBuilder.length() - 1; + if (COMMA_CHAR == jsonBuilder.charAt(lastIndex)) { + jsonBuilder.setCharAt(lastIndex, RIGHT_SQUARE_BRACKET_CHAR); + } else { + jsonBuilder.append(RIGHT_SQUARE_BRACKET_CHAR); } } @@ -151,9 +155,12 @@ private void writeMetadata() { }); } + String toJSON() { + return jsonBuilder.toString(); + } + @Override public SourceVersion getSupportedSourceVersion() { return latestSupported(); } } - \ No newline at end of file diff --git a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/model/util/ConfigurationPropertyJSONElementVisitor.java b/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/ConfigurationPropertyJSONElementVisitor.java similarity index 79% rename from microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/model/util/ConfigurationPropertyJSONElementVisitor.java rename to microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/ConfigurationPropertyJSONElementVisitor.java index 963392408..e30972026 100644 --- a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/model/util/ConfigurationPropertyJSONElementVisitor.java +++ b/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/ConfigurationPropertyJSONElementVisitor.java @@ -15,10 +15,11 @@ * limitations under the License. */ -package io.microsphere.annotation.processor.model.util; +package io.microsphere.annotation.processor; import io.microsphere.annotation.ConfigurationProperty; import io.microsphere.beans.ConfigurationProperty.Metadata; +import io.microsphere.lang.model.util.AnnotatedElementJSONElementVisitor; import io.microsphere.metadata.ConfigurationPropertyGenerator; import javax.annotation.processing.ProcessingEnvironment; @@ -26,18 +27,19 @@ import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.TypeMirror; import java.util.List; import java.util.Map; -import static io.microsphere.annotation.processor.util.AnnotationUtils.getAnnotation; -import static io.microsphere.annotation.processor.util.AnnotationUtils.getAttributeName; -import static io.microsphere.annotation.processor.util.AnnotationUtils.getElementValues; -import static io.microsphere.annotation.processor.util.AnnotationUtils.matchesDefaultAttributeValue; -import static io.microsphere.annotation.processor.util.ClassUtils.getClassName; -import static io.microsphere.annotation.processor.util.TypeUtils.getTypeName; import static io.microsphere.constants.SymbolConstants.COMMA_CHAR; +import static io.microsphere.lang.model.util.AnnotationUtils.getAnnotation; +import static io.microsphere.lang.model.util.AnnotationUtils.getAttributeName; +import static io.microsphere.lang.model.util.AnnotationUtils.getElementValues; +import static io.microsphere.lang.model.util.AnnotationUtils.matchesDefaultAttributeValue; +import static io.microsphere.lang.model.util.ClassUtils.getClassName; +import static io.microsphere.lang.model.util.TypeUtils.getTypeName; import static io.microsphere.util.ServiceLoaderUtils.loadFirstService; import static io.microsphere.util.StringUtils.isBlank; @@ -51,13 +53,13 @@ * @see io.microsphere.beans.ConfigurationProperty * @since 1.0.0 */ -public class ConfigurationPropertyJSONElementVisitor extends AnnotatedElementJSONElementVisitor { +class ConfigurationPropertyJSONElementVisitor extends AnnotatedElementJSONElementVisitor { - public static final String CONFIGURATION_PROPERTY_ANNOTATION_CLASS_NAME = "io.microsphere.annotation.ConfigurationProperty"; + static final String CONFIGURATION_PROPERTY_ANNOTATION_CLASS_NAME = "io.microsphere.annotation.ConfigurationProperty"; private final ConfigurationPropertyGenerator generator; - public ConfigurationPropertyJSONElementVisitor(ProcessingEnvironment processingEnv) { + ConfigurationPropertyJSONElementVisitor(ProcessingEnvironment processingEnv) { super(processingEnv, CONFIGURATION_PROPERTY_ANNOTATION_CLASS_NAME); this.generator = loadFirstService(ConfigurationPropertyGenerator.class); } @@ -87,8 +89,8 @@ public Boolean visitVariableAsField(VariableElement field, StringBuilder jsonBui } else if ("description".equals(attributeName)) { String description = resolveDescription(field, attributeMethod, annotationValue); configurationProperty.setDescription(description); - } else if ("source".equals(attributeName)) { - setSources(configurationProperty, annotationValue); + } else { + setSources(configurationProperty, attributeName, annotationValue); } } setDeclaredClass(configurationProperty, field); @@ -102,6 +104,11 @@ public Boolean visitVariableAsField(VariableElement field, StringBuilder jsonBui return false; } + @Override + protected boolean supportsType(TypeElement e) { + return true; + } + public ConfigurationPropertyGenerator getGenerator() { return generator; } @@ -130,12 +137,14 @@ private String resolveStringValue(ExecutableElement attributeMethod, AnnotationV return (String) value; } - private void setSources(io.microsphere.beans.ConfigurationProperty configurationProperty, AnnotationValue annotationValue) { - List sources = (List) annotationValue.getValue(); - Metadata metadata = configurationProperty.getMetadata(); - for (AnnotationValue source : sources) { - String sourceValue = (String) source.getValue(); - metadata.getSources().add(sourceValue); + void setSources(io.microsphere.beans.ConfigurationProperty configurationProperty, String attributeName, AnnotationValue annotationValue) { + if ("source".equals(attributeName)) { + List sources = (List) annotationValue.getValue(); + Metadata metadata = configurationProperty.getMetadata(); + for (AnnotationValue source : sources) { + String sourceValue = (String) source.getValue(); + metadata.getSources().add(sourceValue); + } } } @@ -149,5 +158,4 @@ private void setDeclaredField(io.microsphere.beans.ConfigurationProperty configu String declaredFieldName = field.getSimpleName().toString(); configurationProperty.getMetadata().setDeclaredField(declaredFieldName); } - -} +} \ No newline at end of file diff --git a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/FilerProcessor.java b/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/FilerProcessor.java index 36d1416b4..5a34c0fa5 100644 --- a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/FilerProcessor.java +++ b/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/FilerProcessor.java @@ -24,7 +24,7 @@ import javax.tools.JavaFileManager; import java.util.function.BiFunction; -import static io.microsphere.annotation.processor.util.MessagerUtils.printMandatoryWarning; +import static io.microsphere.lang.model.util.MessagerUtils.printMandatoryWarning; import static io.microsphere.reflect.FieldUtils.getFieldValue; /** diff --git a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/ResourceProcessor.java b/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/ResourceProcessor.java index ab7b0c883..71852e810 100644 --- a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/ResourceProcessor.java +++ b/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/ResourceProcessor.java @@ -34,8 +34,8 @@ import java.util.function.BiFunction; import java.util.function.Function; -import static io.microsphere.annotation.processor.util.MessagerUtils.printNote; -import static io.microsphere.annotation.processor.util.MessagerUtils.printWarning; +import static io.microsphere.lang.model.util.MessagerUtils.printNote; +import static io.microsphere.lang.model.util.MessagerUtils.printWarning; import static io.microsphere.util.ExceptionUtils.wrap; import static java.util.Optional.empty; import static java.util.Optional.of; diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/ConfigurationPropertyAnnotationProcessorTest.java b/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/ConfigurationPropertyAnnotationProcessorTest.java index 82693aa0f..2e2806fa0 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/ConfigurationPropertyAnnotationProcessorTest.java +++ b/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/ConfigurationPropertyAnnotationProcessorTest.java @@ -17,19 +17,11 @@ package io.microsphere.annotation.processor; -import io.microsphere.annotation.ConfigurationProperty; -import io.microsphere.classloading.ManifestArtifactResourceResolver; -import io.microsphere.io.IOUtils; -import io.microsphere.io.StandardFileWatchService; -import io.microsphere.reflect.MethodUtils; -import io.microsphere.reflect.TypeUtils; -import io.microsphere.util.ServiceLoaderUtils; +import io.microsphere.test.annotation.processing.AbstractAnnotationProcessingTest; import org.junit.jupiter.api.Test; -import java.util.Set; - -import static io.microsphere.annotation.processor.model.util.ConfigurationPropertyJSONElementVisitor.CONFIGURATION_PROPERTY_ANNOTATION_CLASS_NAME; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static io.microsphere.util.Assert.assertNotNull; +import static java.util.Collections.emptySet; /** * {@link ConfigurationPropertyAnnotationProcessor} Test @@ -40,24 +32,12 @@ */ class ConfigurationPropertyAnnotationProcessorTest extends AbstractAnnotationProcessingTest { - @Override - protected void beforeTest() { - super.beforeTest(); - } - - @Override - protected void addCompiledClasses(Set> compiledClasses) { - compiledClasses.add(ManifestArtifactResourceResolver.class); - compiledClasses.add(IOUtils.class); - compiledClasses.add(StandardFileWatchService.class); - compiledClasses.add(TypeUtils.class); - compiledClasses.add(ServiceLoaderUtils.class); - compiledClasses.add(MethodUtils.class); - compiledClasses.add(ConfigurationProperty.class); - } - @Test - void testConstants() { - assertEquals("io.microsphere.annotation.ConfigurationProperty", CONFIGURATION_PROPERTY_ANNOTATION_CLASS_NAME); + void testResolveMetadataOnEmptySet() { + ConfigurationPropertyAnnotationProcessor processor = new ConfigurationPropertyAnnotationProcessor(); + processor.init(super.processingEnv); + processor.resolveMetadata(emptySet()); + String json = processor.toJSON(); + assertNotNull("[]", json); } -} +} \ No newline at end of file diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/ConfigurationPropertyJSONElementVisitorTest.java b/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/ConfigurationPropertyJSONElementVisitorTest.java new file mode 100644 index 000000000..89e4e5deb --- /dev/null +++ b/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/ConfigurationPropertyJSONElementVisitorTest.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.microsphere.annotation.processor; + + +import io.microsphere.annotation.ConfigurationProperty; +import io.microsphere.classloading.ManifestArtifactResourceResolver; +import io.microsphere.io.IOUtils; +import io.microsphere.io.StandardFileWatchService; +import io.microsphere.reflect.MethodUtils; +import io.microsphere.reflect.TypeUtils; +import io.microsphere.test.annotation.processing.AbstractAnnotationProcessingTest; +import io.microsphere.util.ServiceLoaderUtils; +import org.junit.jupiter.api.Test; + +import java.util.Set; + +import static io.microsphere.annotation.processor.ConfigurationPropertyJSONElementVisitor.CONFIGURATION_PROPERTY_ANNOTATION_CLASS_NAME; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link ConfigurationPropertyJSONElementVisitor} Test + * + * @author Mercy + * @see ConfigurationPropertyJSONElementVisitor + * @since 1.0.0 + */ +class ConfigurationPropertyJSONElementVisitorTest extends AbstractAnnotationProcessingTest { + + @Override + protected void addCompiledClasses(Set> compiledClasses) { + compiledClasses.add(ManifestArtifactResourceResolver.class); + compiledClasses.add(IOUtils.class); + compiledClasses.add(StandardFileWatchService.class); + compiledClasses.add(TypeUtils.class); + compiledClasses.add(ServiceLoaderUtils.class); + compiledClasses.add(MethodUtils.class); + compiledClasses.add(ConfigurationProperty.class); + } + + @Test + void testConstants() { + assertEquals("io.microsphere.annotation.ConfigurationProperty", CONFIGURATION_PROPERTY_ANNOTATION_CLASS_NAME); + } + + @Test + void testSupportsType() { + ConfigurationPropertyJSONElementVisitor visitor = new ConfigurationPropertyJSONElementVisitor(super.processingEnv); + assertTrue(visitor.supportsType(super.testTypeElement)); + assertTrue(visitor.supportsType(NULL_TYPE_ELEMENT)); + } + + @Test + void testSetSourcesOnNoSource() { + ConfigurationPropertyJSONElementVisitor visitor = new ConfigurationPropertyJSONElementVisitor(super.processingEnv); + visitor.setSources(null, "noSource", null); + assertNotNull(visitor); + } +} \ No newline at end of file diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/FilerProcessorTest.java b/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/FilerProcessorTest.java index 47588edde..8f715df0f 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/FilerProcessorTest.java +++ b/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/FilerProcessorTest.java @@ -18,10 +18,14 @@ package io.microsphere.annotation.processor; +import io.microsphere.test.annotation.processing.AbstractAnnotationProcessingTest; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ReflectiveInvocationContext; import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; +import java.lang.reflect.Method; import static io.microsphere.annotation.processor.ResourceProcessor.exists; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -40,7 +44,7 @@ class FilerProcessorTest extends AbstractAnnotationProcessingTest { private FilerProcessor processor; @Override - protected void beforeTest() { + protected void beforeTest(ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) { this.processor = new FilerProcessor(super.processingEnv); } diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/ResourceProcessorTest.java b/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/ResourceProcessorTest.java index 35ad93340..1ed22a16d 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/ResourceProcessorTest.java +++ b/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/ResourceProcessorTest.java @@ -18,9 +18,13 @@ package io.microsphere.annotation.processor; +import io.microsphere.test.annotation.processing.AbstractAnnotationProcessingTest; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ReflectiveInvocationContext; import javax.tools.FileObject; +import java.lang.reflect.Method; import java.util.Optional; import static io.microsphere.annotation.processor.ResourceProcessor.FOR_READING; @@ -30,11 +34,14 @@ import static io.microsphere.nio.charset.CharsetUtils.DEFAULT_CHARSET; import static java.lang.Boolean.FALSE; import static java.lang.System.currentTimeMillis; +import static java.util.Optional.empty; import static javax.tools.StandardLocation.CLASS_OUTPUT; import static javax.tools.StandardLocation.SOURCE_PATH; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -56,14 +63,14 @@ class ResourceProcessorTest extends AbstractAnnotationProcessingTest { private String randomResourceName; @Override - protected void beforeTest() { + protected void beforeTest(ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) { this.classOutputProcessor = new ResourceProcessor(super.processingEnv, CLASS_OUTPUT); this.sourcePathProcessor = new ResourceProcessor(super.processingEnv, SOURCE_PATH); this.randomResourceName = "test/" + currentTimeMillis() + ".txt"; } @Override - protected void afterTest() { + protected void afterTest(ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext, Object result, Throwable failure) { this.classOutputProcessor.getResource(this.randomResourceName, FOR_WRITING).ifPresent(FileObject::delete); } @@ -77,6 +84,10 @@ void testProcessInResourceOnFailed() { assertThrows(RuntimeException.class, () -> this.classOutputProcessor.processInResource(this.randomResourceName, FOR_READING, fileObject -> { throw new RuntimeException(); })); + + assertNull(this.classOutputProcessor.processInResource(this.randomResourceName, FOR_READING, fileObject -> { + throw new RuntimeException(); + }, e -> null)); } @Test @@ -97,6 +108,10 @@ void testProcessInResourceInputStreamOnFailed() { assertThrows(RuntimeException.class, () -> this.sourcePathProcessor.processInResourceInputStream(JAVA_SOURCE_RESOURCE_NAME, inputStream -> { throw new RuntimeException(); })); + + assertSame(empty(), this.sourcePathProcessor.processInResourceInputStream(JAVA_SOURCE_RESOURCE_NAME, inputStream -> { + throw new RuntimeException(); + }, (f, e) -> null)); } @Test @@ -111,6 +126,10 @@ void testProcessInResourceReaderOnFailed() { assertThrows(RuntimeException.class, () -> this.sourcePathProcessor.processInResourceReader(JAVA_SOURCE_RESOURCE_NAME, reader -> { throw new RuntimeException(); })); + + assertSame(empty(), this.sourcePathProcessor.processInResourceReader(JAVA_SOURCE_RESOURCE_NAME, reader -> { + throw new RuntimeException(); + }, (f, e) -> null)); } @Test @@ -124,6 +143,10 @@ void testProcessInResourceContentOnFailed() { assertThrows(RuntimeException.class, () -> this.sourcePathProcessor.processInResourceContent(JAVA_SOURCE_RESOURCE_NAME, content -> { throw new RuntimeException(); })); + + assertSame(empty(), this.sourcePathProcessor.processInResourceContent(JAVA_SOURCE_RESOURCE_NAME, content -> { + throw new RuntimeException(); + }, (f, e) -> null)); } @Test @@ -138,6 +161,12 @@ void testProcessInResourceOutputStreamOnFailed() { assertThrows(RuntimeException.class, () -> this.classOutputProcessor.processInResourceOutputStream(this.randomResourceName, outputStream -> { throw new RuntimeException(); })); + + this.classOutputProcessor.processInResourceOutputStream(this.randomResourceName, outputStream -> { + throw new RuntimeException(); + }, (f, e) -> { + assertNotNull(e); + }); } @Test @@ -152,6 +181,12 @@ void testProcessInResourceOnWriterOnFailed() { assertThrows(RuntimeException.class, () -> this.classOutputProcessor.processInResourceWriter(randomResourceName, writer -> { throw new RuntimeException(); })); + + this.classOutputProcessor.processInResourceWriter(this.randomResourceName, writer -> { + throw new RuntimeException(); + }, (f, e) -> { + assertNotNull(e); + }); } @Test diff --git a/microsphere-java-annotations/pom.xml b/microsphere-java-annotations/pom.xml new file mode 100644 index 000000000..e80e54ea5 --- /dev/null +++ b/microsphere-java-annotations/pom.xml @@ -0,0 +1,44 @@ + + + + io.github.microsphere-projects + microsphere-java-parent + ${revision} + ../microsphere-java-parent/pom.xml + + 4.0.0 + + io.github.microsphere-projects + microsphere-java-annotations + ${revision} + jar + + Microsphere :: Java :: Annotations + Microsphere Java Annotations + + + + + + com.google.code.findbugs + jsr305 + true + + + + + org.junit.jupiter + junit-jupiter + test + + + + org.junit.jupiter + junit-jupiter-engine + test + + + + \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/annotation/ConfigurationProperty.java b/microsphere-java-annotations/src/main/java/io/microsphere/annotation/ConfigurationProperty.java similarity index 99% rename from microsphere-java-core/src/main/java/io/microsphere/annotation/ConfigurationProperty.java rename to microsphere-java-annotations/src/main/java/io/microsphere/annotation/ConfigurationProperty.java index dd6272f95..10203087e 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/annotation/ConfigurationProperty.java +++ b/microsphere-java-annotations/src/main/java/io/microsphere/annotation/ConfigurationProperty.java @@ -94,4 +94,4 @@ */ String[] source() default {}; -} +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/annotation/Experimental.java b/microsphere-java-annotations/src/main/java/io/microsphere/annotation/Experimental.java similarity index 99% rename from microsphere-java-core/src/main/java/io/microsphere/annotation/Experimental.java rename to microsphere-java-annotations/src/main/java/io/microsphere/annotation/Experimental.java index 498df0028..e3780f909 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/annotation/Experimental.java +++ b/microsphere-java-annotations/src/main/java/io/microsphere/annotation/Experimental.java @@ -49,4 +49,4 @@ */ String description() default ""; -} +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/annotation/Immutable.java b/microsphere-java-annotations/src/main/java/io/microsphere/annotation/Immutable.java similarity index 99% rename from microsphere-java-core/src/main/java/io/microsphere/annotation/Immutable.java rename to microsphere-java-annotations/src/main/java/io/microsphere/annotation/Immutable.java index 593118b5e..0ae81044f 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/annotation/Immutable.java +++ b/microsphere-java-annotations/src/main/java/io/microsphere/annotation/Immutable.java @@ -31,4 +31,4 @@ @Documented @Retention(RUNTIME) public @interface Immutable { -} +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/annotation/Nonnull.java b/microsphere-java-annotations/src/main/java/io/microsphere/annotation/Nonnull.java similarity index 99% rename from microsphere-java-core/src/main/java/io/microsphere/annotation/Nonnull.java rename to microsphere-java-annotations/src/main/java/io/microsphere/annotation/Nonnull.java index 859ec90a4..0a36bb87a 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/annotation/Nonnull.java +++ b/microsphere-java-annotations/src/main/java/io/microsphere/annotation/Nonnull.java @@ -35,4 +35,4 @@ @javax.annotation.Nonnull @TypeQualifierNickname public @interface Nonnull { -} +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/annotation/Nullable.java b/microsphere-java-annotations/src/main/java/io/microsphere/annotation/Nullable.java similarity index 99% rename from microsphere-java-core/src/main/java/io/microsphere/annotation/Nullable.java rename to microsphere-java-annotations/src/main/java/io/microsphere/annotation/Nullable.java index c3a3a49e0..9b708f889 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/annotation/Nullable.java +++ b/microsphere-java-annotations/src/main/java/io/microsphere/annotation/Nullable.java @@ -36,4 +36,4 @@ @javax.annotation.Nonnull(when = MAYBE) @TypeQualifierNickname public @interface Nullable { -} +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/annotation/Since.java b/microsphere-java-annotations/src/main/java/io/microsphere/annotation/Since.java similarity index 96% rename from microsphere-java-core/src/main/java/io/microsphere/annotation/Since.java rename to microsphere-java-annotations/src/main/java/io/microsphere/annotation/Since.java index bb840ccbc..c2ec0c22d 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/annotation/Since.java +++ b/microsphere-java-annotations/src/main/java/io/microsphere/annotation/Since.java @@ -16,8 +16,6 @@ */ package io.microsphere.annotation; -import io.microsphere.util.Version; - import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; @@ -38,7 +36,6 @@ * The annotation that indicates the API is introduced in the first time. * * @author Mercy - * @see Version * @see Experimental * @since 1.0.0 */ @@ -65,7 +62,7 @@ /** * @return The version value of the API, e.g. 1.0.0 - * @see Version */ String value(); -} + +} \ No newline at end of file diff --git a/microsphere-java-core/src/test/java/io/microsphere/annotation/ConfigurationPropertyTest.java b/microsphere-java-annotations/src/test/java/io/microsphere/annotation/ConfigurationPropertyTest.java similarity index 96% rename from microsphere-java-core/src/test/java/io/microsphere/annotation/ConfigurationPropertyTest.java rename to microsphere-java-annotations/src/test/java/io/microsphere/annotation/ConfigurationPropertyTest.java index 54c7d50c6..c31732d3a 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/annotation/ConfigurationPropertyTest.java +++ b/microsphere-java-annotations/src/test/java/io/microsphere/annotation/ConfigurationPropertyTest.java @@ -25,7 +25,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; /** - * {@link ConfigurationProperty} Test + * {@link ConfigurationProperty @ConfigurationProperty} Test * * @author Mercy * @see ConfigurationProperty diff --git a/microsphere-java-core/src/test/java/io/microsphere/annotation/ExperimentalTest.java b/microsphere-java-annotations/src/test/java/io/microsphere/annotation/ExperimentalTest.java similarity index 96% rename from microsphere-java-core/src/test/java/io/microsphere/annotation/ExperimentalTest.java rename to microsphere-java-annotations/src/test/java/io/microsphere/annotation/ExperimentalTest.java index 9014ea8a9..d4db9a409 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/annotation/ExperimentalTest.java +++ b/microsphere-java-annotations/src/test/java/io/microsphere/annotation/ExperimentalTest.java @@ -21,7 +21,7 @@ import static org.junit.jupiter.api.Assertions.assertNull; /** - * {@link Experimental} Test + * {@link Experimental @Experimental} Test * * @author Mercy * @see Experimental diff --git a/microsphere-java-core/src/test/java/io/microsphere/annotation/ImmutableTest.java b/microsphere-java-annotations/src/test/java/io/microsphere/annotation/ImmutableTest.java similarity index 96% rename from microsphere-java-core/src/test/java/io/microsphere/annotation/ImmutableTest.java rename to microsphere-java-annotations/src/test/java/io/microsphere/annotation/ImmutableTest.java index 5d871cf1d..6ae1ffb79 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/annotation/ImmutableTest.java +++ b/microsphere-java-annotations/src/test/java/io/microsphere/annotation/ImmutableTest.java @@ -22,7 +22,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; /** - * {@link Immutable} Test + * {@link Immutable @Immutable} Test * * @author Mercy * @see Immutable diff --git a/microsphere-java-annotations/src/test/java/io/microsphere/annotation/NonnullTest.java b/microsphere-java-annotations/src/test/java/io/microsphere/annotation/NonnullTest.java new file mode 100644 index 000000000..cea51bd42 --- /dev/null +++ b/microsphere-java-annotations/src/test/java/io/microsphere/annotation/NonnullTest.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.microsphere.annotation; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/** + * {@link Nonnull @Nonnull} Test + * + * @author Mercy + * @see Nonnull + * @since 1.0.0 + */ +@Nonnull +class NonnullTest { + + @Test + void test() { + assertNotNull(NonnullTest.class.getAnnotation(Nonnull.class)); + } +} \ No newline at end of file diff --git a/microsphere-java-annotations/src/test/java/io/microsphere/annotation/NullableTest.java b/microsphere-java-annotations/src/test/java/io/microsphere/annotation/NullableTest.java new file mode 100644 index 000000000..25a6625fe --- /dev/null +++ b/microsphere-java-annotations/src/test/java/io/microsphere/annotation/NullableTest.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.microsphere.annotation; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/** + * {@link Nullable @Nullable} Test + * + * @author Mercy + * @see Nullable + * @since 1.0.0 + */ +@Nullable +class NullableTest { + + @Test + void test() { + assertNotNull(NullableTest.class.getAnnotation(Nullable.class)); + } +} \ No newline at end of file diff --git a/microsphere-java-core/src/test/java/io/microsphere/annotation/SinceTest.java b/microsphere-java-annotations/src/test/java/io/microsphere/annotation/SinceTest.java similarity index 99% rename from microsphere-java-core/src/test/java/io/microsphere/annotation/SinceTest.java rename to microsphere-java-annotations/src/test/java/io/microsphere/annotation/SinceTest.java index 1ecca38c8..1e6314b95 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/annotation/SinceTest.java +++ b/microsphere-java-annotations/src/test/java/io/microsphere/annotation/SinceTest.java @@ -36,4 +36,4 @@ void test() { assertEquals("microsphere-java-core", since.module()); assertEquals("1.0.0", since.value()); } -} +} \ No newline at end of file diff --git a/microsphere-java-core/pom.xml b/microsphere-java-core/pom.xml index c6063daa5..c31c60b8c 100644 --- a/microsphere-java-core/pom.xml +++ b/microsphere-java-core/pom.xml @@ -20,11 +20,11 @@ - + - com.google.code.findbugs - jsr305 - true + io.github.microsphere-projects + microsphere-java-annotations + ${revision} @@ -62,6 +62,13 @@ test
    + + + com.google.code.findbugs + jsr305 + test + + ch.qos.logback diff --git a/microsphere-java-core/src/main/java/io/microsphere/classloading/BannedArtifactClassLoadingExecutor.java b/microsphere-java-core/src/main/java/io/microsphere/classloading/BannedArtifactClassLoadingExecutor.java index 98749c614..4d5f8325a 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/classloading/BannedArtifactClassLoadingExecutor.java +++ b/microsphere-java-core/src/main/java/io/microsphere/classloading/BannedArtifactClassLoadingExecutor.java @@ -81,21 +81,19 @@ public BannedArtifactClassLoadingExecutor(@Nullable ClassLoader classLoader) { } public void execute() { - List bannedArtifactConfigs = loadBannedArtifactConfigs(); + List bannedArtifactConfigs = loadBannedArtifactConfigs(this.classLoader); List artifacts = artifactDetector.detect(false); - for (Artifact artifact : artifacts) { + artifacts.forEach(artifact -> { URL classPathURL = artifact.getLocation(); - if (classPathURL != null) { - for (MavenArtifact bannedArtifactConfig : bannedArtifactConfigs) { - if (bannedArtifactConfig.matches(artifact)) { - removeClassPathURL(classLoader, classPathURL); - } + for (MavenArtifact bannedArtifactConfig : bannedArtifactConfigs) { + if (bannedArtifactConfig.matches(artifact)) { + removeClassPathURL(classLoader, classPathURL); } } - } + }); } - private List loadBannedArtifactConfigs() { + static List loadBannedArtifactConfigs(ClassLoader classLoader) { List bannedArtifactConfigs = new LinkedList<>(); try { Enumeration configResources = classLoader.getResources(CONFIG_LOCATION); @@ -110,7 +108,7 @@ private List loadBannedArtifactConfigs() { return bannedArtifactConfigs; } - private List loadBannedArtifactConfigs(URL configResource) throws IOException { + static List loadBannedArtifactConfigs(URL configResource) throws IOException { List bannedArtifactConfigs = new LinkedList<>(); try (InputStream inputStream = configResource.openStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, ENCODING)) @@ -127,14 +125,10 @@ private List loadBannedArtifactConfigs(URL configResource) throws return bannedArtifactConfigs; } - /** - * @param definition - * @return - */ - private MavenArtifact loadBannedArtifactConfig(String definition) { + static MavenArtifact loadBannedArtifactConfig(String definition) throws IllegalArgumentException { String[] gav = split(definition.trim(), COLON); if (gav.length != 3) { - throw new RuntimeException("The definition of the banned artifact must contain groupId, artifactId and version : " + definition); + throw new IllegalArgumentException("The definition of the banned artifact must contain groupId, artifactId and version : " + definition); } String groupId = gav[0]; String artifactId = gav[1]; diff --git a/microsphere-java-core/src/main/java/io/microsphere/classloading/ManifestArtifactResourceResolver.java b/microsphere-java-core/src/main/java/io/microsphere/classloading/ManifestArtifactResourceResolver.java index b0c616a2e..97f79ff08 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/classloading/ManifestArtifactResourceResolver.java +++ b/microsphere-java-core/src/main/java/io/microsphere/classloading/ManifestArtifactResourceResolver.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; +import java.util.Objects; import java.util.jar.Attributes; import java.util.jar.Manifest; @@ -31,6 +32,7 @@ import static io.microsphere.util.StringUtils.split; import static io.microsphere.util.jar.JarUtils.MANIFEST_RESOURCE_PATH; import static java.lang.System.getProperty; +import static java.util.stream.Stream.of; /** * {@link ArtifactResourceResolver} implementation that reads artifact metadata from JAR manifest files. @@ -197,48 +199,33 @@ protected Artifact resolve(URL resourceURL, InputStream artifactMetadataData, Cl return resolveArtifactMetaInfoInManifest(manifest, resourceURL); } - private Artifact resolveArtifactMetaInfoInManifest(Manifest manifest, URL resourceURL) throws IOException { + Artifact resolveArtifactMetaInfoInManifest(Manifest manifest, URL resourceURL) { Attributes mainAttributes = manifest.getMainAttributes(); - String artifactId = resolveArtifactId(mainAttributes, resourceURL); + String artifactId = resolveArtifactId(mainAttributes); if (artifactId == null) { return null; } String version = resolveVersion(mainAttributes); - return create(artifactId, version, resourceURL); + Artifact artifact = create(artifactId, version, resourceURL); + logger.trace("The artifactId was resolved from the resource URL['{}']: {}", artifactId, artifact); + return artifact; } - private String resolveArtifactId(Attributes attributes, URL artifactResourceURL) { - String artifactId = null; - - for (String artifactIdAttributeName : ARTIFACT_ID_ATTRIBUTE_NAMES) { - artifactId = attributes.getValue(artifactIdAttributeName); - if (artifactId != null) { - break; - } - } - - if (logger.isTraceEnabled()) { - logger.trace("The artifactId was resolved from the '{}' of resource URL['{}'] of : {} , attributes : {}", - MANIFEST_RESOURCE_PATH, - artifactResourceURL.getPath(), - artifactId, - attributes.entrySet() - ); - } - + private String resolveArtifactId(Attributes attributes) { + String artifactId = of(ARTIFACT_ID_ATTRIBUTE_NAMES) + .map(attributes::getValue) + .filter(Objects::nonNull) + .findFirst() + .orElse(null); return artifactId; } private String resolveVersion(Attributes attributes) { - String version = null; - - for (String versionAttributeName : VERSION_ATTRIBUTE_NAMES) { - version = attributes.getValue(versionAttributeName); - if (version != null) { - break; - } - } - + String version = of(VERSION_ATTRIBUTE_NAMES) + .map(attributes::getValue) + .filter(Objects::nonNull) + .findFirst() + .orElse(null); return version; } } diff --git a/microsphere-java-core/src/main/java/io/microsphere/classloading/ServiceLoadingURLClassPathHandle.java b/microsphere-java-core/src/main/java/io/microsphere/classloading/ServiceLoadingURLClassPathHandle.java index 658f679f0..5feb33760 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/classloading/ServiceLoadingURLClassPathHandle.java +++ b/microsphere-java-core/src/main/java/io/microsphere/classloading/ServiceLoadingURLClassPathHandle.java @@ -21,6 +21,7 @@ import static io.microsphere.util.ArrayUtils.isEmpty; import static io.microsphere.util.ServiceLoaderUtils.loadServicesList; +import static java.util.Objects.nonNull; /** * {@link URLClassPathHandle} implementation based on the Service Loading mechanism @@ -34,17 +35,16 @@ public class ServiceLoadingURLClassPathHandle implements URLClassPathHandle { public ServiceLoadingURLClassPathHandle() { List urlClassPathHandles = loadServicesList(URLClassPathHandle.class); - for (URLClassPathHandle urlClassPathHandle : urlClassPathHandles) { - if (urlClassPathHandle.supports()) { - this.delegate = urlClassPathHandle; - break; - } - } + this.delegate = urlClassPathHandles + .stream() + .filter(URLClassPathHandle::supports) + .findFirst() + .orElse(null); } @Override public boolean supports() { - return delegate != null; + return nonNull(this.delegate); } @Override diff --git a/microsphere-java-core/src/main/java/io/microsphere/classloading/StreamArtifactResourceResolver.java b/microsphere-java-core/src/main/java/io/microsphere/classloading/StreamArtifactResourceResolver.java index 052e0bda5..58ed3de1a 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/classloading/StreamArtifactResourceResolver.java +++ b/microsphere-java-core/src/main/java/io/microsphere/classloading/StreamArtifactResourceResolver.java @@ -113,9 +113,7 @@ public final Artifact resolve(URL resourceURL) { Artifact artifact = null; try { if (archiveFile == null) { - if (logger.isTraceEnabled()) { - logger.trace("The resourceURL['{}'] can't be resolved to be an archive file", resourceURL); - } + logger.trace("The resourceURL['{}'] can't be resolved to be an archive file", resourceURL); artifactMetadataData = readArtifactMetadataDataFromResource(resourceURL, classLoader); } else { artifactMetadataData = readArtifactMetadataDataFromArchiveFile(archiveFile); @@ -124,9 +122,7 @@ public final Artifact resolve(URL resourceURL) { artifact = resolve(resourceURL, artifactMetadataData, classLoader); } } catch (IOException e) { - if (logger.isErrorEnabled()) { - logger.error("The Artifact can't be resolved from the resource URL : {}", resourceURL, e); - } + logger.error("The Artifact can't be resolved from the resource URL : {}", resourceURL, e); } finally { // close the InputStream close(artifactMetadataData); @@ -141,13 +137,11 @@ protected InputStream readArtifactMetadataDataFromResource(URL resourceURL, Clas @Nullable protected InputStream readArtifactMetadataDataFromArchiveFile(File archiveFile) throws IOException { - InputStream artifactMetadataData = null; - if (archiveFile.isFile()) { - artifactMetadataData = readArtifactMetadataDataFromFile(archiveFile); - } else if (archiveFile.isDirectory()) { - artifactMetadataData = readArtifactMetadataDataFromDirectory(archiveFile); + if (archiveFile.isDirectory()) { + return readArtifactMetadataDataFromDirectory(archiveFile); + } else { + return readArtifactMetadataDataFromFile(archiveFile); } - return artifactMetadataData; } @Nullable @@ -155,9 +149,7 @@ protected InputStream readArtifactMetadataDataFromFile(File archiveFile) throws JarFile jarFile = new JarFile(archiveFile); JarEntry jarEntry = findArtifactMetadataEntry(jarFile); if (jarEntry == null) { - if (logger.isTraceEnabled()) { - logger.trace("The artifact metadata entry can't be resolved from the JarFile[path: '{}']", archiveFile); - } + logger.trace("The artifact metadata entry can't be resolved from the JarFile[path: '{}']", archiveFile); return null; } return jarFile.getInputStream(jarEntry); @@ -167,9 +159,7 @@ protected InputStream readArtifactMetadataDataFromFile(File archiveFile) throws protected InputStream readArtifactMetadataDataFromDirectory(File directory) throws IOException { File artifactMetadataFile = findArtifactMetadata(directory); if (artifactMetadataFile == null) { - if (logger.isTraceEnabled()) { - logger.trace("The artifact metadata file can't be found in the directory[path: '{}']", directory); - } + logger.trace("The artifact metadata file can't be found in the directory[path: '{}']", directory); return null; } return new FileInputStream(artifactMetadataFile); @@ -197,4 +187,4 @@ protected boolean isArtifactMetadataFile(File directory, File file) { protected abstract boolean isArtifactMetadata(String relativePath); protected abstract Artifact resolve(URL resourceURL, InputStream artifactMetadataData, ClassLoader classLoader) throws IOException; -} +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/collection/DelegatingIterator.java b/microsphere-java-core/src/main/java/io/microsphere/collection/DelegatingIterator.java new file mode 100644 index 000000000..3975f19ab --- /dev/null +++ b/microsphere-java-core/src/main/java/io/microsphere/collection/DelegatingIterator.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.microsphere.collection; + +import io.microsphere.lang.DelegatingWrapper; + +import java.util.Iterator; +import java.util.function.Consumer; + +/** + * A delegating implementation of the {@link Iterator} interface that forwards all method calls to a delegate iterator. + * This class is useful when you want to wrap an existing iterator and potentially override some of its behavior. + * + *

    Example Usage

    + *
    {@code
    + * List list = Arrays.asList("a", "b", "c");
    + * Iterator iterator = new DelegatingIterator<>(list.iterator());
    + * while (iterator.hasNext()) {
    + *     System.out.println(iterator.next());
    + * }
    + * }
    + * + * @param the type of elements returned by this iterator + * @author Mercy + * @see Iterator + */ +public class DelegatingIterator implements Iterator, DelegatingWrapper { + + private final Iterator delegate; + + public DelegatingIterator(Iterator delegate) { + this.delegate = delegate; + } + + @Override + public final boolean hasNext() { + return delegate.hasNext(); + } + + @Override + public final E next() { + return delegate.next(); + } + + @Override + public final void remove() { + delegate.remove(); + } + + @Override + public final void forEachRemaining(Consumer action) { + this.delegate.forEachRemaining(action); + } + + @Override + public final Object getDelegate() { + return this.delegate; + } + + @Override + public final int hashCode() { + return this.delegate.hashCode(); + } + + @Override + public final boolean equals(Object obj) { + return this.delegate.equals(obj); + } + + @Override + public final String toString() { + return this.delegate.toString(); + } +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/collection/EmptyIterator.java b/microsphere-java-core/src/main/java/io/microsphere/collection/EmptyIterator.java index 83f95542d..08514248e 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/collection/EmptyIterator.java +++ b/microsphere-java-core/src/main/java/io/microsphere/collection/EmptyIterator.java @@ -55,31 +55,15 @@ * @see Collections#emptyIterator() */ @Immutable -public class EmptyIterator implements Iterator { +public class EmptyIterator extends DelegatingIterator { /** * The singleton of {@link EmptyIterator} */ public static final EmptyIterator INSTANCE = new EmptyIterator(); - private final Iterator delegate; public EmptyIterator() { - this.delegate = emptyIterator(); - } - - @Override - public boolean hasNext() { - return delegate.hasNext(); - } - - @Override - public E next() { - return delegate.next(); - } - - @Override - public void remove() { - delegate.remove(); + super(emptyIterator()); } } diff --git a/microsphere-java-core/src/main/java/io/microsphere/concurrent/ExecutorUtils.java b/microsphere-java-core/src/main/java/io/microsphere/concurrent/ExecutorUtils.java index a4cfc45e8..930ce67d8 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/concurrent/ExecutorUtils.java +++ b/microsphere-java-core/src/main/java/io/microsphere/concurrent/ExecutorUtils.java @@ -16,6 +16,7 @@ */ package io.microsphere.concurrent; +import io.microsphere.logging.Logger; import io.microsphere.util.ShutdownHookUtils; import io.microsphere.util.Utils; @@ -23,6 +24,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import static io.microsphere.logging.LoggerFactory.getLogger; import static io.microsphere.util.ArrayUtils.forEach; import static io.microsphere.util.ShutdownHookUtils.addShutdownHookCallback; @@ -37,6 +39,8 @@ */ public abstract class ExecutorUtils implements Utils { + private static final Logger logger = getLogger(ExecutorUtils.class); + /** * Registers a shutdown hook to gracefully shut down the given {@link Executor} instances when the JVM exits. * @@ -131,9 +135,10 @@ public static boolean shutdown(ExecutorService executorService) { if (!executorService.isShutdown()) { executorService.shutdown(); } + logger.trace("The ExecutorService({}) has been shutdown", executorService); return true; } private ExecutorUtils() { } -} +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/convert/AbstractConverter.java b/microsphere-java-core/src/main/java/io/microsphere/convert/AbstractConverter.java index 4ce41c1ca..9f465c8ab 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/convert/AbstractConverter.java +++ b/microsphere-java-core/src/main/java/io/microsphere/convert/AbstractConverter.java @@ -21,11 +21,11 @@ import io.microsphere.annotation.Nullable; import io.microsphere.lang.Prioritized; import io.microsphere.logging.Logger; -import io.microsphere.logging.LoggerFactory; import java.util.List; import java.util.Objects; +import static io.microsphere.logging.LoggerFactory.getLogger; import static io.microsphere.util.ClassUtils.getAllClasses; import static io.microsphere.util.ClassUtils.getTypeName; import static io.microsphere.util.ExceptionUtils.wrap; @@ -87,7 +87,7 @@ */ public abstract class AbstractConverter implements Converter { - protected final Logger logger = LoggerFactory.getLogger(getClass()); + protected final Logger logger = getLogger(getClass()); @Nullable private Integer priority; @@ -102,13 +102,11 @@ public final T convert(@Nullable S source) { if (source == null) { return null; } - T target = null; + T target; try { target = doConvert(source); } catch (Throwable e) { - if (logger.isTraceEnabled()) { - logger.trace("The source[value : {}] can't be converted by the Converter[class : '{}']", source, getTypeName(getClass())); - } + logger.warn("The source[value : {}] can't be converted by the Converter[class : '{}']", source, getTypeName(getClass())); throw wrap(e, RuntimeException.class); } return target; @@ -155,7 +153,12 @@ public int getPriority() { @Override public boolean equals(Object o) { - if (!(o instanceof AbstractConverter)) return false; + if (o == this) { + return true; + } + if (!(o instanceof AbstractConverter)) { + return false; + } AbstractConverter that = (AbstractConverter) o; return Objects.equals(getSourceType(), that.getSourceType()) diff --git a/microsphere-java-core/src/main/java/io/microsphere/event/EventListener.java b/microsphere-java-core/src/main/java/io/microsphere/event/EventListener.java index 53bf32623..c85f1a5f2 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/event/EventListener.java +++ b/microsphere-java-core/src/main/java/io/microsphere/event/EventListener.java @@ -22,8 +22,9 @@ import java.lang.reflect.Type; import java.util.Objects; +import static io.microsphere.reflect.TypeUtils.asClass; import static io.microsphere.reflect.TypeUtils.getAllParameterizedTypes; - +import static io.microsphere.reflect.TypeUtils.isAssignableFrom; /** * The {@link Event Event} Listener that is based on Java standard {@link java.util.EventListener} interface supports @@ -128,7 +129,7 @@ static Class findEventType(EventListener listener) { static Class findEventType(Class listenerClass) { Class eventType = null; - if (listenerClass != null && EventListener.class.isAssignableFrom(listenerClass)) { + if (isAssignableFrom(EventListener.class, listenerClass)) { eventType = getAllParameterizedTypes(listenerClass) .stream() .map(EventListener::findEventType) @@ -174,15 +175,13 @@ static Class findEventType(ParameterizedType parameterizedType) Class eventType = null; Type rawType = parameterizedType.getRawType(); - if ((rawType instanceof Class) && EventListener.class.isAssignableFrom((Class) rawType)) { + if (isAssignableFrom(EventListener.class, rawType)) { Type[] typeArguments = parameterizedType.getActualTypeArguments(); for (Type typeArgument : typeArguments) { - if (typeArgument instanceof Class) { - Class argumentClass = (Class) typeArgument; - if (Event.class.isAssignableFrom(argumentClass)) { - eventType = argumentClass; - break; - } + Class argumentClass = asClass(typeArgument); + if (isAssignableFrom(Event.class, argumentClass)) { + eventType = argumentClass; + break; } } } diff --git a/microsphere-java-core/src/main/java/io/microsphere/filter/Filter.java b/microsphere-java-core/src/main/java/io/microsphere/filter/Filter.java index 912e24704..5850f5118 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/filter/Filter.java +++ b/microsphere-java-core/src/main/java/io/microsphere/filter/Filter.java @@ -3,6 +3,8 @@ */ package io.microsphere.filter; +import java.util.function.Predicate; + /** * The {@code Filter} interface represents a generic filtering mechanism that can be applied to objects of type {@code T}. *

    @@ -29,7 +31,7 @@ * @since 1.0.0 */ @FunctionalInterface -public interface Filter { +public interface Filter extends Predicate { /** * Does accept filtered object? @@ -38,4 +40,9 @@ public interface Filter { * @return */ boolean accept(T filteredObject); -} + + @Override + default boolean test(T t) { + return accept(t); + } +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/filter/PackageNameClassFilter.java b/microsphere-java-core/src/main/java/io/microsphere/filter/PackageNameClassFilter.java index e77237aa7..c0e313cc9 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/filter/PackageNameClassFilter.java +++ b/microsphere-java-core/src/main/java/io/microsphere/filter/PackageNameClassFilter.java @@ -24,7 +24,9 @@ public class PackageNameClassFilter implements ClassFilter { private final String packageName; + private final boolean includedSubPackages; + private final String subPackageNamePrefix; /** diff --git a/microsphere-java-core/src/main/java/io/microsphere/io/FastByteArrayInputStream.java b/microsphere-java-core/src/main/java/io/microsphere/io/FastByteArrayInputStream.java index a297812dc..46a799ce2 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/io/FastByteArrayInputStream.java +++ b/microsphere-java-core/src/main/java/io/microsphere/io/FastByteArrayInputStream.java @@ -110,17 +110,20 @@ public int read(byte[] b, int off, int len) { throw new IndexOutOfBoundsException(); } - if (pos >= count) { - return -1; + if (len == 0) { + return 0; } int avail = count - pos; + + if (avail < 1) { + return -1; + } + if (len > avail) { len = avail; } - if (len <= 0) { - return 0; - } + arraycopy(buf, pos, b, off, len); pos += len; return len; diff --git a/microsphere-java-core/src/main/java/io/microsphere/io/FileUtils.java b/microsphere-java-core/src/main/java/io/microsphere/io/FileUtils.java index b8ca0539e..b11cf416a 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/io/FileUtils.java +++ b/microsphere-java-core/src/main/java/io/microsphere/io/FileUtils.java @@ -10,17 +10,18 @@ import io.microsphere.util.Utils; import java.io.File; -import java.io.FileNotFoundException; import java.io.IOException; +import java.nio.file.NoSuchFileException; -import static io.microsphere.constants.FileConstants.FILE_EXTENSION_CHAR; +import static io.microsphere.constants.FileConstants.FILE_EXTENSION; import static io.microsphere.constants.PathConstants.SLASH_CHAR; import static io.microsphere.constants.SymbolConstants.DOT_CHAR; import static io.microsphere.lang.function.ThrowableSupplier.execute; import static io.microsphere.util.ArrayUtils.isEmpty; import static io.microsphere.util.CharSequenceUtils.isEmpty; -import static io.microsphere.util.StringUtils.isBlank; +import static io.microsphere.util.StringUtils.substringAfterLast; import static java.io.File.separatorChar; +import static java.nio.file.Files.delete; import static java.nio.file.Files.isSymbolicLink; /** @@ -97,11 +98,7 @@ public static String resolveRelativePath(File parentDirectory, File targetFile) */ @Nullable public static String getFileExtension(String fileName) { - if (isBlank(fileName)) { - return null; - } - int index = fileName.lastIndexOf(FILE_EXTENSION_CHAR); - return index > -1 ? fileName.substring(index + 1) : null; + return substringAfterLast(fileName, FILE_EXTENSION); } /** @@ -164,17 +161,8 @@ public static int deleteDirectory(File directory) throws IOException { */ public static int cleanDirectory(File directory) throws IOException { int deletedFilesCount = 0; - IOException exception = null; for (File file : listFiles(directory)) { - try { - deletedFilesCount += forceDelete(file); - } catch (IOException ioe) { - exception = ioe; - } - } - - if (null != exception) { - throw exception; + deletedFilesCount += forceDelete(file); } return deletedFilesCount; } @@ -190,30 +178,22 @@ public static int cleanDirectory(File directory) throws IOException { *

  • {@code forceDelete(new File("/tmp/file.txt"))} deletes the file and returns {@code 1}
  • *
  • {@code forceDelete(new File("/tmp/testDir"))} deletes the directory and all its contents, * returning the total count of deleted files and directories.
  • - *
  • {@code forceDelete(new File("/nonexistent/file"))} throws a {@link FileNotFoundException}
  • + *
  • {@code forceDelete(new File("/nonexistent/file"))} throws a {@link NoSuchFileException}
  • * * * @param file the file or directory to delete, must not be {@code null} * @return the number of deleted files and directories - * @throws NullPointerException if the file is {@code null} - * @throws FileNotFoundException if the file does not exist - * @throws IOException if deletion fails for any reason + * @throws NullPointerException if the file is {@code null} + * @throws NoSuchFileException if the file does not exist + * @throws IOException if deletion fails for any reason */ - public static int forceDelete(File file) throws IOException { + public static int forceDelete(File file) throws NoSuchFileException, IOException { final int deletedFilesCount; if (file.isDirectory()) { deletedFilesCount = deleteDirectory(file); } else { - boolean filePresent = file.exists(); - if (file.delete()) { - deletedFilesCount = 1; - } else { - if (!filePresent) { - throw new FileNotFoundException("File does not exist: " + file); - } - String message = "Unable to delete file: " + file; - throw new IOException(message); - } + delete(file.toPath()); + deletedFilesCount = 1; } return deletedFilesCount; } diff --git a/microsphere-java-core/src/main/java/io/microsphere/io/IOUtils.java b/microsphere-java-core/src/main/java/io/microsphere/io/IOUtils.java index 424454bff..c5bd0b47e 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/io/IOUtils.java +++ b/microsphere-java-core/src/main/java/io/microsphere/io/IOUtils.java @@ -367,9 +367,7 @@ public static int copy(InputStream in, OutputStream out) throws IOException { byteCount += bytesRead; } out.flush(); - if (logger.isTraceEnabled()) { - logger.trace("Copied {} bytes[buffer size : {}] from InputStream[{}] to OutputStream[{}]", byteCount, BUFFER_SIZE, in, out); - } + logger.trace("Copied {} bytes[buffer size : {}] from InputStream[{}] to OutputStream[{}]", byteCount, BUFFER_SIZE, in, out); return byteCount; } diff --git a/microsphere-java-core/src/main/java/io/microsphere/io/StandardFileWatchService.java b/microsphere-java-core/src/main/java/io/microsphere/io/StandardFileWatchService.java index 052a8a5f1..ba892d397 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/io/StandardFileWatchService.java +++ b/microsphere-java-core/src/main/java/io/microsphere/io/StandardFileWatchService.java @@ -22,6 +22,7 @@ import io.microsphere.io.event.FileChangedEvent; import io.microsphere.io.event.FileChangedEvent.Kind; import io.microsphere.io.event.FileChangedListener; +import io.microsphere.logging.Logger; import java.io.File; import java.nio.file.FileSystem; @@ -36,7 +37,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import static io.microsphere.annotation.ConfigurationProperty.SYSTEM_PROPERTIES_SOURCE; import static io.microsphere.collection.MapUtils.newTreeMap; @@ -49,6 +50,9 @@ import static io.microsphere.io.event.FileChangedEvent.Kind.CREATED; import static io.microsphere.io.event.FileChangedEvent.Kind.DELETED; import static io.microsphere.io.event.FileChangedEvent.Kind.MODIFIED; +import static io.microsphere.logging.LoggerFactory.getLogger; +import static io.microsphere.text.FormatUtils.format; +import static io.microsphere.util.ArrayUtils.arrayToString; import static io.microsphere.util.ArrayUtils.length; import static java.lang.System.getProperty; import static java.nio.file.FileSystems.getDefault; @@ -57,8 +61,8 @@ import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE; import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; -import static java.nio.file.StandardWatchEventKinds.OVERFLOW; import static java.util.concurrent.Executors.newSingleThreadExecutor; +import static java.util.concurrent.TimeUnit.MILLISECONDS; /** * /** @@ -103,6 +107,8 @@ */ public class StandardFileWatchService implements FileWatchService, AutoCloseable { + private static final Logger logger = getLogger(StandardFileWatchService.class); + /** * The default thread name prefix : "microsphere-file-watch-service" */ @@ -124,7 +130,7 @@ public class StandardFileWatchService implements FileWatchService, AutoCloseable ) public static final String THREAD_NAME_PREFIX = getProperty(THREAD_NAME_PREFIX_PROPERTY_NAME, DEFAULT_THREAD_NAME_PREFIX); - private static final WatchEvent.Kind[] ALL_WATCH_EVENT_KINDS = { + static final WatchEvent.Kind[] ALL_WATCH_EVENT_KINDS = { ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY @@ -132,15 +138,15 @@ public class StandardFileWatchService implements FileWatchService, AutoCloseable private WatchService watchService; - private final ExecutorService eventLoopExecutor; - private final Executor eventHandlerExecutor; + private final ExecutorService eventLoopExecutor; + private final Map fileChangedMetadataCache = newTreeMap(); - private volatile boolean started; + private final AtomicBoolean started; - private Future eventLoopFuture; + private volatile Future eventLoopFuture; public StandardFileWatchService() { this(DIRECT_EXECUTOR); @@ -151,18 +157,19 @@ public StandardFileWatchService(Executor eventHandlerExecutor) { } public StandardFileWatchService(Executor eventHandlerExecutor, ExecutorService eventLoopExecutor) { - this.eventLoopExecutor = eventLoopExecutor; this.eventHandlerExecutor = eventHandlerExecutor; + this.eventLoopExecutor = eventLoopExecutor; + this.started = new AtomicBoolean(false); // shutdown the ExecutorService when JVM exits shutdownOnExit(eventLoopExecutor, eventHandlerExecutor); } public void start() throws Exception { - if (started) { + if (!this.started.compareAndSet(false, true)) { throw new IllegalStateException("StandardFileWatchService has started"); } - started = true; + logger.info("Start to watch the file system."); FileSystem fileSystem = getDefault(); @@ -176,9 +183,32 @@ public void start() throws Exception { } + public void stop() throws Exception { + // set the flag "started" to false + while (this.started.compareAndSet(true, false)) { + // wait for the event loop to complete + this.eventLoopExecutor.awaitTermination(100, MILLISECONDS); + // if the event loop is not done, try to cancel the task + this.eventLoopFuture.cancel(true); + } + } + + public boolean isStarted() { + return this.started.get(); + } + + @Override + public void close() throws Exception { + this.stop(); + IOUtils.close(this.watchService); + this.fileChangedMetadataCache.clear(); + shutdown(this.eventLoopExecutor); + shutdown(this.eventHandlerExecutor); + } + private void dispatchFileChangedEvents(WatchService watchService) { - eventLoopFuture = eventLoopExecutor.submit(() -> { - while (started) { + this.eventLoopFuture = this.eventLoopExecutor.submit(() -> { + while (isStarted()) { WatchKey watchKey = null; try { watchKey = watchService.take(); @@ -188,7 +218,8 @@ private void dispatchFileChangedEvents(WatchService watchService) { Path dirPath = (Path) watchable; Path fileRelativePath = (Path) event.context(); - FileChangedMetadata metadata = fileChangedMetadataCache.get(dirPath); + FileChangedMetadata metadata = this.fileChangedMetadataCache.get(dirPath); + if (metadata != null) { Path filePath = dirPath.resolve(fileRelativePath); if (isDirectory(dirPath, NOFOLLOW_LINKS) || metadata.filePaths.contains(filePath)) { @@ -214,14 +245,17 @@ private void dispatchFileChangedEvent(Path filePath, WatchEvent.Kind watchEventK Kind kind = toKind(watchEventKind); FileChangedEvent fileChangedEvent = new FileChangedEvent(file, kind); eventDispatcher.dispatch(fileChangedEvent); + logger.trace("The {} was dispatched", fileChangedEvent); } private void registerDirectoriesToWatchService(WatchService watchService) throws Exception { - for (Map.Entry entry : fileChangedMetadataCache.entrySet()) { + for (Map.Entry entry : this.fileChangedMetadataCache.entrySet()) { Path directoryPath = entry.getKey(); FileChangedMetadata metadata = entry.getValue(); WatchEvent.Kind[] kinds = metadata.watchEventKinds; directoryPath.register(watchService, kinds); + logger.trace("The directory[path : '{}' , event kinds : {}] registers the WatchService : {}", + directoryPath, arrayToString(kinds), watchService); } } @@ -235,7 +269,7 @@ public void watch(File file, FileChangedListener listener, Kind... kinds) { private FileChangedMetadata getMetadata(Path filePath, Kind... kinds) { final Path dirPath = isDirectory(filePath, NOFOLLOW_LINKS) ? filePath : filePath.getParent(); - return fileChangedMetadataCache.computeIfAbsent(dirPath, k -> { + return this.fileChangedMetadataCache.computeIfAbsent(dirPath, k -> { FileChangedMetadata metadata = new FileChangedMetadata(); metadata.eventDispatcher = parallel(this.eventHandlerExecutor); metadata.watchEventKinds = toWatchEventKinds(kinds); @@ -244,7 +278,7 @@ private FileChangedMetadata getMetadata(Path filePath, Kind... kinds) { } @Nonnull - private WatchEvent.Kind[] toWatchEventKinds(Kind[] kinds) { + static WatchEvent.Kind[] toWatchEventKinds(Kind... kinds) { int size = length(kinds); if (size < 1) { return ALL_WATCH_EVENT_KINDS; @@ -258,8 +292,8 @@ private WatchEvent.Kind[] toWatchEventKinds(Kind[] kinds) { } @Nonnull - private WatchEvent.Kind toWatchEventKind(Kind kind) { - WatchEvent.Kind watchEventKind = OVERFLOW; + static WatchEvent.Kind toWatchEventKind(Kind kind) { + final WatchEvent.Kind watchEventKind; switch (kind) { case CREATED: watchEventKind = ENTRY_CREATE; @@ -267,7 +301,7 @@ private WatchEvent.Kind toWatchEventKind(Kind kind) { case MODIFIED: watchEventKind = ENTRY_MODIFY; break; - case DELETED: + default: watchEventKind = ENTRY_DELETE; break; } @@ -275,42 +309,21 @@ private WatchEvent.Kind toWatchEventKind(Kind kind) { } @Nonnull - private Kind toKind(WatchEvent.Kind watchEventKind) { + static Kind toKind(WatchEvent.Kind watchEventKind) { final Kind kind; if (ENTRY_CREATE.equals(watchEventKind)) { kind = CREATED; } else if (ENTRY_MODIFY.equals(watchEventKind)) { kind = MODIFIED; - } else { + } else if (ENTRY_DELETE.equals(watchEventKind)) { kind = DELETED; + } else { + String errorMessage = format("The invalid kind of WatchEvent : {}", watchEventKind); + throw new IllegalArgumentException(errorMessage); } return kind; } - public void stop() throws Exception { - if (started) { - // set the flag "started" to false - started = false; - // wait for the event loop to complete - if (!eventLoopExecutor.awaitTermination(100, TimeUnit.MILLISECONDS)) { - // if the event loop is not done, try to cancel the task - eventLoopFuture.cancel(true); - } - - if (watchService != null) { - watchService.close(); - } - fileChangedMetadataCache.clear(); - shutdown(eventLoopExecutor); - shutdown(eventHandlerExecutor); - } - } - - @Override - public void close() throws Exception { - this.stop(); - } - private static class FileChangedMetadata { private final Set filePaths = new TreeSet<>(); @@ -320,4 +333,4 @@ private static class FileChangedMetadata { private WatchEvent.Kind[] watchEventKinds; } -} +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/io/filter/NameFileFilter.java b/microsphere-java-core/src/main/java/io/microsphere/io/filter/NameFileFilter.java index 1e53e2231..c71c2032d 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/io/filter/NameFileFilter.java +++ b/microsphere-java-core/src/main/java/io/microsphere/io/filter/NameFileFilter.java @@ -46,4 +46,4 @@ public boolean accept(File file) { String name = this.name; return caseSensitive ? fileName.equals(name) : fileName.equalsIgnoreCase(name); } -} +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/json/JSONStringer.java b/microsphere-java-core/src/main/java/io/microsphere/json/JSONStringer.java index 832787050..37c6dbd51 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/json/JSONStringer.java +++ b/microsphere-java-core/src/main/java/io/microsphere/json/JSONStringer.java @@ -21,6 +21,11 @@ import static io.microsphere.json.JSONObject.NULL; import static io.microsphere.json.JSONObject.numberToString; +import static io.microsphere.json.JSONStringer.Scope.DANGLING_KEY; +import static io.microsphere.json.JSONStringer.Scope.EMPTY_ARRAY; +import static io.microsphere.json.JSONStringer.Scope.EMPTY_OBJECT; +import static io.microsphere.json.JSONStringer.Scope.NONEMPTY_ARRAY; +import static io.microsphere.json.JSONStringer.Scope.NONEMPTY_OBJECT; import static io.microsphere.util.ClassUtils.getTypeName; import static java.util.Arrays.fill; @@ -145,7 +150,7 @@ public JSONStringer(int indentSpaces) { * @throws JSONException if processing of json failed */ public JSONStringer array() throws JSONException { - return open(Scope.EMPTY_ARRAY, "["); + return open(EMPTY_ARRAY, "["); } /** @@ -155,7 +160,7 @@ public JSONStringer array() throws JSONException { * @throws JSONException if processing of json failed */ public JSONStringer endArray() throws JSONException { - return close(Scope.EMPTY_ARRAY, Scope.NONEMPTY_ARRAY, "]"); + return close(EMPTY_ARRAY, NONEMPTY_ARRAY, "]"); } /** @@ -166,7 +171,7 @@ public JSONStringer endArray() throws JSONException { * @throws JSONException if processing of json failed */ public JSONStringer object() throws JSONException { - return open(Scope.EMPTY_OBJECT, "{"); + return open(EMPTY_OBJECT, "{"); } /** @@ -176,7 +181,7 @@ public JSONStringer object() throws JSONException { * @throws JSONException if processing of json failed */ public JSONStringer endObject() throws JSONException { - return close(Scope.EMPTY_OBJECT, Scope.NONEMPTY_OBJECT, "}"); + return close(EMPTY_OBJECT, NONEMPTY_OBJECT, "}"); } /** @@ -188,7 +193,7 @@ public JSONStringer endObject() throws JSONException { * @throws JSONException if processing of json failed */ JSONStringer open(Scope empty, String openBracket) throws JSONException { - if (this.stack.isEmpty() && this.out.length() > 0) { + if (isEmpty() && this.out.length() > 0) { throw new JSONException("Nesting problem: multiple top-level roots"); } beforeValue(); @@ -228,7 +233,7 @@ JSONStringer close(Scope empty, Scope nonempty, String closeBracket) throws JSON * @throws JSONException if processing of json failed */ private Scope peek() throws JSONException { - if (this.stack.isEmpty()) { + if (isEmpty()) { throw new JSONException("Nesting problem"); } return this.stack.get(this.stack.size() - 1); @@ -253,7 +258,7 @@ private void replaceTop(Scope topOfStack) { * @throws JSONException if processing of json failed */ public JSONStringer value(Object value) throws JSONException { - if (this.stack.isEmpty()) { + if (isEmpty()) { throw new JSONException("Nesting problem"); } @@ -288,7 +293,7 @@ public JSONStringer value(Object value) throws JSONException { * @throws JSONException if processing of json failed */ public JSONStringer value(boolean value) throws JSONException { - if (this.stack.isEmpty()) { + if (isEmpty()) { throw new JSONException("Nesting problem"); } beforeValue(); @@ -305,7 +310,7 @@ public JSONStringer value(boolean value) throws JSONException { * @throws JSONException if processing of json failed */ public JSONStringer value(double value) throws JSONException { - if (this.stack.isEmpty()) { + if (isEmpty()) { throw new JSONException("Nesting problem"); } beforeValue(); @@ -321,7 +326,7 @@ public JSONStringer value(double value) throws JSONException { * @throws JSONException if processing of json failed */ public JSONStringer value(long value) throws JSONException { - if (this.stack.isEmpty()) { + if (isEmpty()) { throw new JSONException("Nesting problem"); } beforeValue(); @@ -414,13 +419,13 @@ public JSONStringer key(String name) throws JSONException { */ void beforeKey() throws JSONException { Scope context = peek(); - if (context == Scope.NONEMPTY_OBJECT) { // first in object + if (context == NONEMPTY_OBJECT) { // first in object this.out.append(','); - } else if (context != Scope.EMPTY_OBJECT) { // not in an object! + } else if (context != EMPTY_OBJECT) { // not in an object! throw new JSONException("Nesting problem"); } newline(); - replaceTop(Scope.DANGLING_KEY); + replaceTop(DANGLING_KEY); } /** @@ -431,20 +436,20 @@ void beforeKey() throws JSONException { * @throws JSONException if processing of json failed */ void beforeValue() throws JSONException { - if (this.stack.isEmpty()) { + if (isEmpty()) { return; } Scope context = peek(); - if (context == Scope.EMPTY_ARRAY) { // first in array - replaceTop(Scope.NONEMPTY_ARRAY); + if (context == EMPTY_ARRAY) { // first in array + replaceTop(NONEMPTY_ARRAY); newline(); - } else if (context == Scope.NONEMPTY_ARRAY) { // another in array + } else if (context == NONEMPTY_ARRAY) { // another in array this.out.append(','); newline(); - } else if (context == Scope.DANGLING_KEY) { // value for key + } else if (context == DANGLING_KEY) { // value for key this.out.append(this.indent == null ? ":" : ": "); - replaceTop(Scope.NONEMPTY_OBJECT); + replaceTop(NONEMPTY_OBJECT); } else if (context != Scope.NULL) { throw new JSONException("Nesting problem"); } @@ -466,4 +471,7 @@ public String toString() { return this.out.length() == 0 ? null : this.out.toString(); } + boolean isEmpty() { + return this.stack.isEmpty(); + } } diff --git a/microsphere-java-core/src/main/java/io/microsphere/json/JSONTokener.java b/microsphere-java-core/src/main/java/io/microsphere/json/JSONTokener.java index ac6e4318a..f17066c58 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/json/JSONTokener.java +++ b/microsphere-java-core/src/main/java/io/microsphere/json/JSONTokener.java @@ -19,6 +19,10 @@ import static io.microsphere.json.JSONObject.NULL; import static java.lang.Boolean.FALSE; import static java.lang.Boolean.TRUE; +import static java.lang.Double.valueOf; +import static java.lang.Integer.MAX_VALUE; +import static java.lang.Integer.MIN_VALUE; +import static java.lang.Long.parseLong; /** * Parses a JSON (RFC 4627) encoded @@ -117,8 +121,8 @@ public Object nextValue() throws JSONException { } int nextCleanInternal() throws JSONException { - while (this.pos < this.in.length()) { - int c = this.in.charAt(this.pos++); + while (hasNext()) { + int c = nextChar(); switch (c) { case '\t': case ' ': @@ -131,7 +135,7 @@ int nextCleanInternal() throws JSONException { return c; } - char peek = this.in.charAt(this.pos); + char peek = currentChar(); switch (peek) { case '*': // skip a /* c-style comment */ @@ -175,8 +179,8 @@ int nextCleanInternal() throws JSONException { * terminated by "\r\n", the '\n' must be consumed as whitespace by the caller. */ void skipToEndOfLine() { - for (; this.pos < this.in.length(); this.pos++) { - char c = this.in.charAt(this.pos); + for (; hasNext(); this.pos++) { + char c = currentChar(); if (c == '\r' || c == '\n') { this.pos++; break; @@ -206,8 +210,8 @@ public String nextString(char quote) throws JSONException { /* the index of the first character not yet appended to the builder. */ int start = this.pos; - while (this.pos < this.in.length()) { - int c = this.in.charAt(this.pos++); + while (hasNext()) { + int c = nextChar(); if (c == quote) { if (builder == null) { // a new string avoids leaking memory @@ -244,7 +248,7 @@ public String nextString(char quote) throws JSONException { * @throws JSONException if processing of json failed */ char readEscapeCharacter() throws JSONException { - char escaped = this.in.charAt(this.pos++); + char escaped = nextChar(); switch (escaped) { case 'u': if (this.pos + 4 > this.in.length()) { @@ -309,8 +313,8 @@ public Object readLiteral() throws JSONException { base = 8; } try { - long longValue = Long.parseLong(number, base); - if (longValue <= Integer.MAX_VALUE && longValue >= Integer.MIN_VALUE) { + long longValue = parseLong(number, base); + if (longValue <= MAX_VALUE && longValue >= MIN_VALUE) { return (int) longValue; } else { return longValue; @@ -326,7 +330,7 @@ public Object readLiteral() throws JSONException { /* ...next try to parse as a floating point... */ try { - return Double.valueOf(literal); + return valueOf(literal); } catch (NumberFormatException ignored) { } @@ -343,8 +347,8 @@ public Object readLiteral() throws JSONException { */ String nextToInternal(String excluded) { int start = this.pos; - for (; this.pos < this.in.length(); this.pos++) { - char c = this.in.charAt(this.pos); + for (; hasNext(); this.pos++) { + char c = currentChar(); if (c == '\r' || c == '\n' || excluded.indexOf(c) != -1) { return this.in.substring(start, this.pos); } @@ -389,7 +393,7 @@ public JSONObject readObject() throws JSONException { if (separator != ':' && separator != '=') { throw syntaxError("Expected ':' after " + name); } - if (this.pos < this.in.length() && this.in.charAt(this.pos) == '>') { + if (hasNext() && currentChar() == '>') { this.pos++; } @@ -486,11 +490,15 @@ public String toString() { */ public boolean more() { - return this.pos < this.in.length(); + return hasNext(); } public char next() { - return this.pos < this.in.length() ? this.in.charAt(this.pos++) : '\0'; + return hasNext() ? nextChar() : '\0'; + } + + public boolean hasNext() { + return this.pos < this.in.length(); } public char next(char c) throws JSONException { @@ -547,6 +555,18 @@ public void back() { } } + char currentChar() { + return charAt(this.pos); + } + + char nextChar() { + return charAt(this.pos++); + } + + char charAt(int pos) { + return this.in.charAt(pos); + } + public static int dehexchar(char hex) { if (hex >= '0' && hex <= '9') { return hex - '0'; @@ -559,4 +579,4 @@ public static int dehexchar(char hex) { } } -} +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/lang/ClassDataRepository.java b/microsphere-java-core/src/main/java/io/microsphere/lang/ClassDataRepository.java index 05961ed23..812b135ff 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/lang/ClassDataRepository.java +++ b/microsphere-java-core/src/main/java/io/microsphere/lang/ClassDataRepository.java @@ -21,11 +21,6 @@ import io.microsphere.annotation.Nullable; import io.microsphere.util.ClassPathUtils; -import java.io.File; -import java.net.MalformedURLException; -import java.net.URL; -import java.security.CodeSource; -import java.security.ProtectionDomain; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; @@ -38,7 +33,6 @@ import static io.microsphere.util.ClassPathUtils.getClassPaths; import static io.microsphere.util.ClassUtils.findClassNamesInClassPath; import static io.microsphere.util.ClassUtils.resolvePackageName; -import static io.microsphere.util.StringUtils.isNotBlank; import static java.util.Collections.emptySet; import static java.util.Collections.unmodifiableMap; import static java.util.Collections.unmodifiableSet; @@ -94,9 +88,6 @@ public class ClassDataRepository { private final Map> packageNameToClassNamesMap = initPackageNameToClassNamesMap(); - private ClassDataRepository() { - } - /** * Get all package names in {@link ClassPathUtils#getClassPaths() class paths} * @@ -199,35 +190,6 @@ public Set getAllClassNamesInClassPaths() { return unmodifiableSet(allClassNames); } - /** - * Get {@link Class}'s code source location URL - * - * @param type - * @return If , return null. - * @throws NullPointerException If type is null , {@link NullPointerException} will be thrown. - */ - public URL getCodeSourceLocation(Class type) throws NullPointerException { - - URL codeSourceLocation = null; - ClassLoader classLoader = type.getClassLoader(); - - if (classLoader == null) { // Bootstrap ClassLoader or type is primitive or void - String path = findClassPath(type); - if (isNotBlank(path)) { - try { - codeSourceLocation = new File(path).toURI().toURL(); - } catch (MalformedURLException ignored) { - codeSourceLocation = null; - } - } - } else { - ProtectionDomain protectionDomain = type.getProtectionDomain(); - CodeSource codeSource = protectionDomain == null ? null : protectionDomain.getCodeSource(); - codeSourceLocation = codeSource == null ? null : codeSource.getLocation(); - } - return codeSourceLocation; - } - @Nonnull @Immutable private Map> initClassPathToClassNamesMap() { @@ -280,4 +242,7 @@ private Map> initPackageNameToClassNamesMap() { return unmodifiableMap(packageNameToClassNamesMap); } -} + + private ClassDataRepository() { + } +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/lang/Deprecation.java b/microsphere-java-core/src/main/java/io/microsphere/lang/Deprecation.java index a19eb0a01..135c872e8 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/lang/Deprecation.java +++ b/microsphere-java-core/src/main/java/io/microsphere/lang/Deprecation.java @@ -26,6 +26,7 @@ import static io.microsphere.constants.SymbolConstants.QUOTE_CHAR; import static io.microsphere.lang.Deprecation.Level.DEFAULT; +import static io.microsphere.util.Assert.assertNotNull; import static java.util.Objects.hash; /** @@ -96,12 +97,13 @@ public final class Deprecation implements Serializable { } Deprecation(@Nullable Version since, @Nullable String replacement, @Nullable String reason, - @Nullable String link, @Nullable Level level) { + @Nullable String link, @Nonnull Level level) { + assertNotNull(level, () -> "the 'level' must not be null"); this.since = since; this.replacement = replacement; this.reason = reason; this.link = link; - this.level = level == null ? DEFAULT : level; + this.level = level; } @Nullable @@ -129,10 +131,14 @@ public Level getLevel() { return level; } - @Override public boolean equals(Object o) { - if (!(o instanceof Deprecation)) return false; + if (o == this) { + return true; + } + if (!(o instanceof Deprecation)) { + return false; + } Deprecation that = (Deprecation) o; return Objects.equals(since, that.since) && Objects.equals(replacement, that.replacement) @@ -270,4 +276,4 @@ public static Deprecation of(String since, String replacement, String reason, St .level(level) .build(); } -} +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/logging/LoggerFactory.java b/microsphere-java-core/src/main/java/io/microsphere/logging/LoggerFactory.java index 1ffe2c503..2adadb1ed 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/logging/LoggerFactory.java +++ b/microsphere-java-core/src/main/java/io/microsphere/logging/LoggerFactory.java @@ -21,9 +21,11 @@ import io.microsphere.lang.Prioritized; import java.util.List; +import java.util.function.Predicate; import static io.microsphere.collection.ListUtils.newLinkedList; import static java.util.Collections.sort; +import static java.util.Objects.nonNull; import static java.util.ServiceLoader.load; /** @@ -74,7 +76,8 @@ private static LoggerFactory loadFactory() { static List loadAvailableFactories() { List factories = loadFactories(); - factories.removeIf(factory -> !factory.isAvailable()); + Predicate predicate = LoggerFactory::isAvailable; + factories.removeIf(predicate.negate()); return factories; } @@ -112,7 +115,7 @@ public static Logger getLogger(String name) { * @return true if available */ protected boolean isAvailable() { - return getDelegateLoggerClass() != null; + return nonNull(getDelegateLoggerClass()); } /** diff --git a/microsphere-java-core/src/main/java/io/microsphere/management/ManagementUtils.java b/microsphere-java-core/src/main/java/io/microsphere/management/ManagementUtils.java index b14fa3f49..e96d8e662 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/management/ManagementUtils.java +++ b/microsphere-java-core/src/main/java/io/microsphere/management/ManagementUtils.java @@ -1,14 +1,12 @@ package io.microsphere.management; -import io.microsphere.logging.Logger; import io.microsphere.process.ProcessIdResolver; import io.microsphere.util.ServiceLoaderUtils; import io.microsphere.util.Utils; -import java.util.List; +import java.util.Objects; -import static io.microsphere.logging.LoggerFactory.getLogger; import static io.microsphere.process.ProcessIdResolver.UNKNOWN_PROCESS_ID; import static io.microsphere.util.ServiceLoaderUtils.loadServicesList; @@ -22,29 +20,16 @@ */ public abstract class ManagementUtils implements Utils { - private static final Logger logger = getLogger(ManagementUtils.class); - static final long currentProcessId = resolveCurrentProcessId(); private static long resolveCurrentProcessId() { - List resolvers = loadServicesList(ProcessIdResolver.class); - Long processId = null; - for (ProcessIdResolver resolver : resolvers) { - if (resolver.supports()) { - if ((processId = resolver.current()) != null) { - log(resolver, processId); - break; - } - } - } - return processId == null ? UNKNOWN_PROCESS_ID : processId; - } - - static void log(ProcessIdResolver resolver, Long processId) { - if (logger.isTraceEnabled()) { - logger.trace("The process id was resolved by ProcessIdResolver[class : '{}' , priority : {}] successfully : {}", - resolver.getClass().getName(), resolver.getPriority(), processId); - } + return loadServicesList(ProcessIdResolver.class) + .stream() + .filter(ProcessIdResolver::supports) + .map(ProcessIdResolver::current) + .filter(Objects::nonNull) + .findFirst() + .orElse(UNKNOWN_PROCESS_ID); } /** @@ -75,4 +60,4 @@ public static long getCurrentProcessId() { private ManagementUtils() { } -} +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/net/ServiceLoaderURLStreamHandlerFactory.java b/microsphere-java-core/src/main/java/io/microsphere/net/ServiceLoaderURLStreamHandlerFactory.java index ece8723fe..debae146f 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/net/ServiceLoaderURLStreamHandlerFactory.java +++ b/microsphere-java-core/src/main/java/io/microsphere/net/ServiceLoaderURLStreamHandlerFactory.java @@ -30,7 +30,6 @@ import static io.microsphere.collection.MapUtils.toFixedMap; import static io.microsphere.net.URLUtils.attachURLStreamHandlerFactory; import static io.microsphere.util.ServiceLoaderUtils.loadServicesList; -import static java.util.Collections.emptyMap; /** * A {@link URLStreamHandlerFactory} implementation that uses the JDK's {@link ServiceLoader} @@ -84,18 +83,10 @@ private static URLStreamHandlerFactory createDelegate() { @Nonnull @Immutable - private static Map loadHandlers() { + static Map loadHandlers() { List handlers = loadServicesList(ExtendableProtocolURLStreamHandler.class); - - int size = handlers.size(); - if (size < 1) { - return emptyMap(); - } - Map handlersMap = toFixedMap( handlers, handler -> immutableEntry(handler.getProtocol(), handler)); - return handlersMap; - } -} +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/net/StandardURLStreamHandlerFactory.java b/microsphere-java-core/src/main/java/io/microsphere/net/StandardURLStreamHandlerFactory.java index 7656ad31a..9a23d0c79 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/net/StandardURLStreamHandlerFactory.java +++ b/microsphere-java-core/src/main/java/io/microsphere/net/StandardURLStreamHandlerFactory.java @@ -26,9 +26,10 @@ import static io.microsphere.constants.SymbolConstants.DOT; import static io.microsphere.logging.LoggerFactory.getLogger; import static io.microsphere.net.URLUtils.DEFAULT_HANDLER_PACKAGE_PREFIX; -import static io.microsphere.reflect.AccessibleObjectUtils.trySetAccessible; import static io.microsphere.reflect.FieldUtils.findField; -import static java.lang.Class.forName; +import static io.microsphere.reflect.FieldUtils.getStaticFieldValue; +import static io.microsphere.util.ClassLoaderUtils.resolveClass; +import static io.microsphere.util.ClassUtils.newInstance; /** * Standard implementation of {@link URLStreamHandlerFactory} that creates a new instance of @@ -68,35 +69,28 @@ public class StandardURLStreamHandlerFactory implements URLStreamHandlerFactory @Override public URLStreamHandler createURLStreamHandler(String protocol) { - URLStreamHandler handler = createURLStreamHandlerFromDefaultFactory(protocol); + return createURLStreamHandler(defaultFactoryField, protocol); + } + + URLStreamHandler createURLStreamHandler(Field defaultFactoryField, String protocol) { + URLStreamHandler handler = createURLStreamHandlerFromDefaultFactory(defaultFactoryField, protocol); if (handler == null) { // <= JDK 8 works String name = DEFAULT_HANDLER_PACKAGE_PREFIX + DOT + protocol + DOT + "Handler"; - try { - Object o = forName(name).newInstance(); - return (URLStreamHandler) o; - } catch (Exception x) { - // For compatibility, all Exceptions are ignored. - // any number of exceptions can get thrown here + Class handlerClass = resolveClass(name); + if (handlerClass != null) { + handler = (URLStreamHandler) newInstance(handlerClass); } } return handler; } - URLStreamHandler createURLStreamHandlerFromDefaultFactory(String protocol) { + URLStreamHandler createURLStreamHandlerFromDefaultFactory(Field defaultFactoryField, String protocol) { if (defaultFactoryField == null) { - if (logger.isTraceEnabled()) { - logger.trace("The 'defaultFactory' field can't be found in the class URL."); - } + logger.trace("The 'defaultFactory' field can't be found in the class URL."); return null; } - URLStreamHandler handler = null; - try { - trySetAccessible(defaultFactoryField); - URLStreamHandlerFactory factory = (URLStreamHandlerFactory) defaultFactoryField.get(null); - handler = factory.createURLStreamHandler(protocol); - } catch (Exception e) { - // ignore - } + URLStreamHandlerFactory factory = getStaticFieldValue(defaultFactoryField); + URLStreamHandler handler = factory.createURLStreamHandler(protocol); return handler; } -} +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/net/URLUtils.java b/microsphere-java-core/src/main/java/io/microsphere/net/URLUtils.java index e17f7fc67..30c07b58d 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/net/URLUtils.java +++ b/microsphere-java-core/src/main/java/io/microsphere/net/URLUtils.java @@ -12,7 +12,6 @@ import io.microsphere.util.Utils; import java.io.File; -import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; @@ -25,10 +24,10 @@ import java.util.Map; import java.util.Set; import java.util.StringJoiner; -import java.util.jar.JarEntry; import java.util.jar.JarFile; import static io.microsphere.collection.CollectionUtils.size; +import static io.microsphere.collection.ListUtils.first; import static io.microsphere.collection.Lists.ofList; import static io.microsphere.collection.MapUtils.isEmpty; import static io.microsphere.collection.MapUtils.newFixedLinkedHashMap; @@ -40,6 +39,7 @@ import static io.microsphere.constants.ProtocolConstants.FILE_PROTOCOL; import static io.microsphere.constants.ProtocolConstants.JAR_PROTOCOL; import static io.microsphere.constants.ProtocolConstants.WAR_PROTOCOL; +import static io.microsphere.constants.ProtocolConstants.ZIP_PROTOCOL; import static io.microsphere.constants.SeparatorConstants.ARCHIVE_ENTRY_SEPARATOR; import static io.microsphere.constants.SymbolConstants.AND_CHAR; import static io.microsphere.constants.SymbolConstants.COLON; @@ -60,15 +60,18 @@ import static io.microsphere.util.StringUtils.isBlank; import static io.microsphere.util.StringUtils.replace; import static io.microsphere.util.StringUtils.split; +import static io.microsphere.util.StringUtils.substringAfter; import static io.microsphere.util.StringUtils.substringAfterLast; import static io.microsphere.util.SystemUtils.FILE_ENCODING; import static io.microsphere.util.SystemUtils.IS_OS_WINDOWS; -import static io.microsphere.util.jar.JarUtils.resolveRelativePath; +import static io.microsphere.util.jar.JarUtils.isDirectoryEntry; +import static io.microsphere.util.jar.JarUtils.toJarFile; import static java.lang.Character.isWhitespace; import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; import static java.util.Collections.unmodifiableList; import static java.util.Collections.unmodifiableMap; +import static java.util.Objects.nonNull; /** * {@link URL} Utility class @@ -243,85 +246,6 @@ public static String resolveBasePath(URL url) throws NullPointerException { return resolvePath(url, false); } - static String resolvePath(URL url, boolean includeArchiveEntryPath) { - String protocol = url.getProtocol(); - - switch (protocol) { - case FILE_PROTOCOL: - return resolvePathFromFile(url); - case JAR_PROTOCOL: - return resolvePathFromJar(url, includeArchiveEntryPath); - } - - String path = url.getPath(); - - // path may contain the matrix parameters - int indexOfMatrixString = indexOfMatrixString(path); - // path removes the matrix parameters if present - path = indexOfMatrixString > -1 ? path.substring(0, indexOfMatrixString) : path; - - return path; - } - - static String resolvePathFromFile(URL url) { - String path = buildPath(url); - if (IS_OS_WINDOWS) { - int index = path.indexOf(SLASH_CHAR); - if (index == 0) { - path = path.substring(1); - } - } - return path; - } - - static String buildPath(URL url) { - String authority = url.getAuthority(); - String path = url.getPath(); - int length = 0; - int authorityLength = length(authority); - if (authorityLength > 0) { - length += authority.length() + 1; - } - int pathLength = length(path); - if (pathLength > 0) { - length += pathLength; - } - StringBuilder pathBuilder = new StringBuilder(length); - if (authorityLength > 0) { - pathBuilder.append(SLASH_CHAR) - .append(authority); - } - if (pathLength > 0) { - pathBuilder.append(path); - } - return pathBuilder.toString(); - } - - static String resolvePathFromJar(URL url, boolean includeArchiveEntryPath) { - String path = buildPath(url); - int filePrefixIndex = path.indexOf(FILE_URL_PREFIX); - if (filePrefixIndex == 0) { // path starts with "file:/" - path = path.substring(FILE_URL_PREFIX_LENGTH); - } - - // path removes the archive entry path if present - if (!includeArchiveEntryPath) { - int indexOfArchiveEntry = indexOfArchiveEntry(path); - path = indexOfArchiveEntry > -1 ? path.substring(0, indexOfArchiveEntry) : path; - } - - int indexOfColon = path.indexOf(COLON_CHAR); - if (indexOfColon == -1) { // the path on the Unix/Linux - // path adds the leading slash if not present - int indexOfSlash = path.indexOf(SLASH_CHAR); - if (indexOfSlash != 0) { - path = SLASH_CHAR + path; - } - } // else the path on the Windows - - return path; - } - /** * Resolves the archive file from the specified URL. * @@ -363,7 +287,7 @@ protected static File doResolveArchiveFile(URL url) throws NullPointerException } protected static File resolveArchiveDirectory(URL resourceURL) { - String resourcePath = new File(resourceURL.getFile()).toString(); + String resourcePath = buildPath(resourceURL); Set classPaths = getClassPaths(); File archiveDirectory = null; for (String classPath : classPaths) { @@ -695,28 +619,18 @@ public static String decode(String value, String encoding) throws IllegalArgumen * @throws NullPointerException if the provided URL is {@code null} */ public static boolean isDirectoryURL(URL url) { - boolean isDirectory = false; - if (url != null) { - String protocol = url.getProtocol(); - try { - if (JAR_PROTOCOL.equals(protocol)) { - JarFile jarFile = toJarFile(url); // Test whether valid jar or not - final String relativePath = resolveRelativePath(url); - if (EMPTY.equals(relativePath)) { // root directory in jar - isDirectory = true; - } else { - JarEntry jarEntry = jarFile.getJarEntry(relativePath); - isDirectory = jarEntry != null && jarEntry.isDirectory(); - } - } else if (FILE_PROTOCOL.equals(protocol)) { - File classPathFile = new File(url.toURI()); - isDirectory = classPathFile.isDirectory(); - } - } catch (Exception e) { - isDirectory = false; - } + if (url == null) { + return false; + } + if (isDirectoryEntry(url)) { + return true; + } + String protocol = url.getProtocol(); + if (FILE_PROTOCOL.equals(protocol)) { + File classPathFile = new File(buildPath(url)); + return classPathFile.isDirectory(); } - return isDirectory; + return false; } /** @@ -754,7 +668,7 @@ public static boolean isJarURL(URL url) { boolean flag = false; if (FILE_PROTOCOL.equals(protocol)) { JarFile jarFile = toJarFile(url); - flag = jarFile != null; + flag = nonNull(jarFile); } else if (JAR_PROTOCOL.equals(protocol)) { flag = true; } @@ -797,73 +711,43 @@ public static boolean isJarURL(URL url) { * @throws NullPointerException if the provided URL is {@code null}. */ public static boolean isArchiveURL(URL url) { - String protocol = url.getProtocol(); - boolean flag = false; - switch (protocol) { - case JAR_PROTOCOL: - case WAR_PROTOCOL: - case EAR_PROTOCOL: - flag = true; - break; - case FILE_PROTOCOL: - JarFile jarFile = toJarFile(url); - flag = jarFile != null; + if (isJarURL(url)) { + return true; } - return flag; + String protocol = url.getProtocol(); + return isArchiveProtocol(protocol); } /** - * Converts the provided URL to a {@link JarFile} instance if it refers to a valid JAR file. + * Determines whether the specified protocol represents an archive type. * - *

    This method attempts to open the URL as a JAR file. If the URL uses the "file" protocol, - * it checks whether the corresponding file exists and is a valid JAR. For other protocols (e.g., "jar"), - * it tries to extract and open the underlying JAR file.

    + *

    This method checks if the given protocol matches known archive protocols such as "jar", "zip", "war", or "ear". + * These protocols are commonly used to reference compressed or packaged resources.

    * *

    Example Usage

    *
    {@code
    -     * // Example 1: Valid JAR file URL
    -     * URL jarURL = new URL("file:/path/to/archive.jar");
    -     * JarFile jarFile = URLUtils.toJarFile(jarURL);
    -     * if (jarFile != null) {
    -     *     System.out.println("Successfully opened JAR file.");
    -     * } else {
    -     *     System.out.println("Failed to open JAR file.");
    -     * }
    +     * // Valid archive protocols
    +     * boolean result = URLUtils.isArchiveProtocol("jar");
    +     * System.out.println(result); // Output: true
    +     *
    +     * result = URLUtils.isArchiveProtocol("war");
    +     * System.out.println(result); // Output: true
          *
    -     * // Example 2: Invalid JAR file URL
    -     * URL invalidURL = new URL("file:/path/to/invalid.jar");
    -     * jarFile = URLUtils.toJarFile(invalidURL);
    -     * System.out.println(jarFile == null); // Output: true
    +     * // Non-archive protocol
    +     * result = URLUtils.isArchiveProtocol("http");
    +     * System.out.println(result); // Output: false
          *
    -     * // Example 3: URL with "jar" protocol
    -     * URL urlWithJarProtocol = new URL("jar:file:/path/to/archive.jar!/entry/path");
    -     * jarFile = URLUtils.toJarFile(urlWithJarProtocol);
    -     * System.out.println(jarFile != null); // Output: true
    +     * // Case-sensitive check
    +     * result = URLUtils.isArchiveProtocol("JAR");
    +     * System.out.println(result); // Output: false
          * }
    * - * @param url The URL to convert into a JAR file. - * @return A non-null {@link JarFile} if the URL refers to a valid JAR file; otherwise, returns {@code null}. - * @throws NullPointerException if the provided URL is {@code null}. + * @param protocol The protocol string to check. + * @return {@code true} if the protocol is an archive type; otherwise, {@code false}. */ - @Nullable - public static JarFile toJarFile(URL url) { - String path = buildPath(url); - File file = new File(path); - if (!file.exists()) { - if (logger.isTraceEnabled()) { - logger.trace("The JarFile is not existed from the url : {}", url); - } - return null; - } - JarFile jarFile = null; - try { - jarFile = new JarFile(file); - } catch (IOException e) { - if (logger.isTraceEnabled()) { - logger.trace("The JarFile can't be open from the url : {}", url); - } - } - return jarFile; + public static boolean isArchiveProtocol(String protocol) { + return JAR_PROTOCOL.equals(protocol) || ZIP_PROTOCOL.equals(protocol) || WAR_PROTOCOL.equals(protocol) + || EAR_PROTOCOL.equals(protocol); } /** @@ -1641,6 +1525,86 @@ public static void close(URLConnection conn) { } } + static String resolvePath(URL url, boolean includeArchiveEntryPath) { + String protocol = url.getProtocol(); + + switch (protocol) { + case FILE_PROTOCOL: + return resolvePathFromFile(url); + case JAR_PROTOCOL: + return resolvePathFromJar(url, includeArchiveEntryPath); + } + + String path = url.getPath(); + + // path may contain the matrix parameters + int indexOfMatrixString = indexOfMatrixString(path); + // path removes the matrix parameters if present + path = indexOfMatrixString > -1 ? path.substring(0, indexOfMatrixString) : path; + + return path; + } + + static String resolvePathFromFile(URL url) { + return resolvePathFromFile(url, IS_OS_WINDOWS); + } + + static String resolvePathFromFile(URL url, boolean isOsWindows) { + String path = buildPath(url); + if (isOsWindows) { + path = substringAfter(path, SLASH); + } + return path; + } + + static String buildPath(URL url) { + String authority = url.getAuthority(); + String path = url.getPath(); + int length = 0; + int authorityLength = length(authority); + if (authorityLength > 0) { + length += authority.length() + 1; + } + int pathLength = length(path); + if (pathLength > 0) { + length += pathLength; + } + StringBuilder pathBuilder = new StringBuilder(length); + if (authorityLength > 0) { + pathBuilder.append(SLASH_CHAR) + .append(authority); + } + if (pathLength > 0) { + pathBuilder.append(path); + } + return pathBuilder.toString(); + } + + static String resolvePathFromJar(URL url, boolean includeArchiveEntryPath) { + String path = buildPath(url); + int filePrefixIndex = path.indexOf(FILE_URL_PREFIX); + if (filePrefixIndex == 0) { // path starts with "file:/" + path = path.substring(FILE_URL_PREFIX_LENGTH); + } + + // path removes the archive entry path if present + if (!includeArchiveEntryPath) { + int indexOfArchiveEntry = indexOfArchiveEntry(path); + path = indexOfArchiveEntry > -1 ? path.substring(0, indexOfArchiveEntry) : path; + } + + int indexOfColon = path.indexOf(COLON_CHAR); + if (indexOfColon == -1) { // the path on the Unix/Linux + // path adds the leading slash if not present + int indexOfSlash = path.indexOf(SLASH_CHAR); + if (indexOfSlash != 0) { + path = SLASH_CHAR + path; + } + } // else the path on the Windows + + return path; + } + static String resolvePath(String value, int indexOfMatrixString) { return indexOfMatrixString > -1 ? value.substring(0, indexOfMatrixString) : value; } @@ -1766,7 +1730,7 @@ protected static String buildString(String name, String[] values, char separator protected static String getFirst(Map> parameters, String name) { List values = parameters.get(name); - return values == null || values.isEmpty() ? null : values.get(0); + return first(values); } private static int indexOfArchiveEntry(String path) { @@ -1775,4 +1739,4 @@ private static int indexOfArchiveEntry(String path) { private URLUtils() { } -} +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/process/ClassicProcessIdResolver.java b/microsphere-java-core/src/main/java/io/microsphere/process/ClassicProcessIdResolver.java index 7a1ce136c..10ff9f6ac 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/process/ClassicProcessIdResolver.java +++ b/microsphere-java-core/src/main/java/io/microsphere/process/ClassicProcessIdResolver.java @@ -82,9 +82,7 @@ public boolean supports() { @Override public Long current() { Long processId = valueOf(processIdValue); - if (logger.isTraceEnabled()) { - logger.trace("The PID was resolved from the method 'java.lang.management.RuntimeMXBean#getName()' = {} : {}", runtimeName, processId); - } + logger.trace("The PID was resolved from the method 'java.lang.management.RuntimeMXBean#getName()' = {} : {}", runtimeName, processId); return processId; } @@ -92,4 +90,4 @@ public Long current() { public int getPriority() { return NORMAL_PRIORITY + 9; } -} +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/process/ModernProcessIdResolver.java b/microsphere-java-core/src/main/java/io/microsphere/process/ModernProcessIdResolver.java index 6a138378d..c1c606418 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/process/ModernProcessIdResolver.java +++ b/microsphere-java-core/src/main/java/io/microsphere/process/ModernProcessIdResolver.java @@ -22,6 +22,7 @@ import static io.microsphere.reflect.MethodUtils.invokeMethod; import static io.microsphere.reflect.MethodUtils.invokeStaticMethod; import static io.microsphere.util.ClassLoaderUtils.resolveClass; +import static java.util.Objects.nonNull; /** * A {@link ProcessIdResolver} implementation for modern JDKs (Java 9+). @@ -56,16 +57,14 @@ public class ModernProcessIdResolver implements ProcessIdResolver { @Override public boolean supports() { - return PROCESS_HANDLE_CLASS != null; + return nonNull(PROCESS_HANDLE_CLASS); } @Override public Long current() { Object processHandle = invokeStaticMethod(PROCESS_HANDLE_CLASS, "current"); Long pid = invokeMethod(processHandle, PROCESS_HANDLE_CLASS, "pid"); - if (logger.isTraceEnabled()) { - logger.trace("The PID was resolved from the method 'java.lang.ProcessHandle#pid()' : {}", pid); - } + logger.trace("The PID was resolved from the method 'java.lang.ProcessHandle#pid()' : {}", pid); return pid; } diff --git a/microsphere-java-core/src/main/java/io/microsphere/process/ProcessExecutor.java b/microsphere-java-core/src/main/java/io/microsphere/process/ProcessExecutor.java index f74674d7e..5c49e3f10 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/process/ProcessExecutor.java +++ b/microsphere-java-core/src/main/java/io/microsphere/process/ProcessExecutor.java @@ -1,18 +1,34 @@ package io.microsphere.process; +import io.microsphere.annotation.ConfigurationProperty; +import io.microsphere.io.FastByteArrayInputStream; +import io.microsphere.io.FastByteArrayOutputStream; +import io.microsphere.logging.Logger; + import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import static io.microsphere.annotation.ConfigurationProperty.SYSTEM_PROPERTIES_SOURCE; +import static io.microsphere.concurrent.CustomizedThreadFactory.newThreadFactory; +import static io.microsphere.concurrent.ExecutorUtils.shutdownOnExit; import static io.microsphere.constants.SymbolConstants.SPACE_CHAR; +import static io.microsphere.io.IOUtils.copy; +import static io.microsphere.logging.LoggerFactory.getLogger; import static io.microsphere.process.ProcessManager.INSTANCE; import static io.microsphere.text.FormatUtils.format; import static io.microsphere.util.ArrayUtils.isNotEmpty; -import static java.lang.Long.MAX_VALUE; +import static io.microsphere.util.ExceptionUtils.wrap; import static java.lang.Long.getLong; +import static java.lang.Long.parseLong; import static java.lang.Runtime.getRuntime; -import static java.lang.System.currentTimeMillis; +import static java.util.concurrent.Executors.newSingleThreadExecutor; +import static java.util.concurrent.TimeUnit.MILLISECONDS; /** * {@link Process} Executor @@ -43,17 +59,45 @@ */ public class ProcessExecutor { - private static final long waitForTimeInSecond = getLong("process.executor.wait.for", 1); + private static final Logger logger = getLogger(ProcessExecutor.class); + + /** + * The default proeprty value for the timeout of process execution : 30 seconds + */ + public static final String DEFAULT_PROCESS_EXECUTION_TIMEOUT_PROPERTY_VAUE = "30000"; + + /** + * The default value for the timeout of process execution : 30 seconds + */ + public static final long DEFAULT_PROCESS_EXECUTION_TIMEOUT = parseLong(DEFAULT_PROCESS_EXECUTION_TIMEOUT_PROPERTY_VAUE); + + /** + * The property name for the timeout of process execution : "process.execution.timeout" + * + * @see #DEFAULT_PROCESS_EXECUTION_TIMEOUT_PROPERTY_VAUE + * @see #DEFAULT_PROCESS_EXECUTION_TIMEOUT + */ + @ConfigurationProperty( + type = long.class, + defaultValue = DEFAULT_PROCESS_EXECUTION_TIMEOUT_PROPERTY_VAUE, + source = SYSTEM_PROPERTIES_SOURCE + ) + public static final String PROCESS_EXECUTION_TIMEOUT_PROPERTY_NAME = "process.execution.timeout"; + + /** + * the timeout of process execution + */ + public static final long DEFAULT_TIMEOUT = getLong(PROCESS_EXECUTION_TIMEOUT_PROPERTY_NAME, DEFAULT_PROCESS_EXECUTION_TIMEOUT); private final ProcessManager processManager = INSTANCE; private final Runtime runtime = getRuntime(); - private final String commandLine; - private final String options; - private boolean finished; + private final String commandLine; + + private final ExecutorService executor; /** * Constructor @@ -69,28 +113,24 @@ public ProcessExecutor(String command, String... options) { } } this.options = optionsBuilder.toString(); + this.executor = newSingleThreadExecutor(newThreadFactory("process-exec", true)); this.commandLine = command + this.options; + shutdownOnExit(this.executor); } /** * Execute current process. - *

    - * // * @param inputStream input stream keeps output stream from process * * @param outputStream output stream for process normal or error input stream. - * @throws IOException if process execution is failed. + * @throws IOException if process execution is failed. + * @throws TimeoutException if the execution is timeout over specified {@link #DEFAULT_TIMEOUT} */ - public void execute(OutputStream outputStream) throws IOException { - try { - this.execute(outputStream, MAX_VALUE); - } catch (TimeoutException e) { - } + public void execute(OutputStream outputStream) throws IOException, TimeoutException { + this.execute(outputStream, DEFAULT_TIMEOUT); } /** * Execute current process. - *

    - * // * @param inputStream input stream keeps output stream from process * * @param outputStream output stream for process normal or error input stream. * @param timeoutInMilliseconds milliseconds timeout @@ -98,64 +138,54 @@ public void execute(OutputStream outputStream) throws IOException { * @throws TimeoutException if the execution is timeout over specified timeoutInMilliseconds */ public void execute(OutputStream outputStream, long timeoutInMilliseconds) throws IOException, TimeoutException { - Process process = runtime.exec(commandLine); - long startTime = currentTimeMillis(); - long endTime = -1L; - InputStream processInputStream = process.getInputStream(); - InputStream processErrorInputStream = process.getErrorStream(); -// OutputStream processOutputStream = process.getOutputStream(); - int exitValue = -1; - while (!finished) { - long costTime = endTime - startTime; - if (costTime > timeoutInMilliseconds) { - finished = true; - processManager.destroy(process); - String message = format("Execution is timeout[{} ms]!", timeoutInMilliseconds); - throw new TimeoutException(message); - } + execute(outputStream, timeoutInMilliseconds, MILLISECONDS); + } + + /** + * Execute current process. + * + * @param outputStream output stream for process normal or error input stream. + * @param timeout the timeout value + * @param timeUnit {@link TimeUnit} + * @throws IOException if process execution is failed. + * @throws TimeoutException if the execution is timeout over specified timeout and timeUnit + */ + public void execute(OutputStream outputStream, long timeout, TimeUnit timeUnit) throws IOException, TimeoutException { + + Future future = executor.submit(() -> { + Process process = runtime.exec(commandLine); + InputStream processInputStream = process.getInputStream(); + InputStream processErrorInputStream = process.getErrorStream(); + FastByteArrayOutputStream targetOutputStream = new FastByteArrayOutputStream(); + int exitValue = -1; try { processManager.addUnfinishedProcess(process, options); - while (processInputStream.available() > 0) { - outputStream.write(processInputStream.read()); - } - while (processErrorInputStream.available() > 0) { - outputStream.write(processErrorInputStream.read()); - } + // Copy the standard input stream + copy(processInputStream, targetOutputStream); + // Copy the error input stream + copy(processErrorInputStream, targetOutputStream); + + // wait for the process being executed + process.waitFor(timeout, timeUnit); + + // try to exit with value exitValue = process.exitValue(); if (exitValue != 0) { - throw new IOException(); + String message = format("The command['{}'] execution is exited with invalid value : {}", commandLine, exitValue); + throw new IOException(message); } - finished = true; - } catch (IllegalThreadStateException e) { - // Process is not finished yet; - // Sleep a little to save on CPU cycles - waitFor(waitForTimeInSecond); - endTime = currentTimeMillis(); } finally { processManager.removeUnfinishedProcess(process, options); + logger.trace("The command['{}'] is executed with exit value : {}", commandLine, exitValue); } - } - } + return targetOutputStream.toByteArray(); + }); - /** - * Wait for specified seconds - * - * @param seconds specified seconds - */ - private void waitFor(long seconds) { try { - Thread.sleep(seconds * 1000); - } catch (InterruptedException e) { - Thread.interrupted(); + byte[] bytes = future.get(timeout, timeUnit); + copy(new FastByteArrayInputStream(bytes), outputStream); + } catch (InterruptedException | ExecutionException e) { + throw wrap(e, IOException.class); } } - - /** - * Check current process finish or not. - * - * @return true if current process finished - */ - public boolean isFinished() { - return finished; - } -} +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/process/ProcessManager.java b/microsphere-java-core/src/main/java/io/microsphere/process/ProcessManager.java index 1166e2609..55f41d857 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/process/ProcessManager.java +++ b/microsphere-java-core/src/main/java/io/microsphere/process/ProcessManager.java @@ -44,7 +44,10 @@ public class ProcessManager { */ public static final ProcessManager INSTANCE = new ProcessManager(); - private final ConcurrentMap unfinishedProcessesCache = new ConcurrentHashMap<>(); + final ConcurrentMap unfinishedProcessesCache = new ConcurrentHashMap<>(); + + private ProcessManager() { + } protected ProcessManager addUnfinishedProcess(Process process, String arguments) { unfinishedProcessesCache.putIfAbsent(process, arguments); @@ -56,10 +59,6 @@ protected ProcessManager removeUnfinishedProcess(Process process, String argumen return this; } - public void destroy(Process process) { - process.destroy(); - } - /** * Unfinished Processes Map * @@ -70,4 +69,4 @@ public void destroy(Process process) { public Map unfinishedProcessesMap() { return unmodifiableMap(unfinishedProcessesCache); } -} +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/process/VirtualMachineProcessIdResolver.java b/microsphere-java-core/src/main/java/io/microsphere/process/VirtualMachineProcessIdResolver.java index ddfa97746..a2e48bbba 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/process/VirtualMachineProcessIdResolver.java +++ b/microsphere-java-core/src/main/java/io/microsphere/process/VirtualMachineProcessIdResolver.java @@ -27,6 +27,7 @@ import static io.microsphere.reflect.FieldUtils.getFieldValue; import static io.microsphere.reflect.MethodUtils.invokeMethod; import static java.lang.Long.valueOf; +import static java.util.Objects.nonNull; /** * A {@link ProcessIdResolver} implementation for retrieving the process ID using the SUN JVM internal APIs. @@ -81,7 +82,7 @@ public class VirtualMachineProcessIdResolver implements ProcessIdResolver { @Override public boolean supports() { - return JVM_FIELD != null; + return nonNull(JVM_FIELD); } @Override @@ -89,9 +90,7 @@ public Long current() { RuntimeMXBean runtimeMXBean = getRuntimeMXBean(); Object jvm = getFieldValue(runtimeMXBean, JVM_FIELD); Integer processId = invokeMethod(jvm, GET_PROCESS_ID_METHOD_NAME); - if (logger.isTraceEnabled()) { - logger.trace("The PID was resolved from the native method 'sun.management.VMManagementImpl#getProcessId()' : {}", processId); - } + logger.trace("The PID was resolved from the native method 'sun.management.VMManagementImpl#getProcessId()' : {}", processId); return valueOf(processId.longValue()); } diff --git a/microsphere-java-core/src/main/java/io/microsphere/reflect/AccessibleObjectUtils.java b/microsphere-java-core/src/main/java/io/microsphere/reflect/AccessibleObjectUtils.java index 4bb741d3b..d6ea3d485 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/reflect/AccessibleObjectUtils.java +++ b/microsphere-java-core/src/main/java/io/microsphere/reflect/AccessibleObjectUtils.java @@ -167,7 +167,7 @@ static boolean setAccessible(AccessibleObject accessibleObject) { return accessible; } - private static boolean trySetAccessible(MethodHandle methodHandle, AccessibleObject accessibleObject) { + static boolean trySetAccessible(MethodHandle methodHandle, AccessibleObject accessibleObject) { boolean accessible = false; try { accessible = (boolean) methodHandle.invokeExact(accessibleObject); @@ -177,11 +177,15 @@ private static boolean trySetAccessible(MethodHandle methodHandle, AccessibleObj return accessible; } - private static Boolean tryCanAccess(Object object, AccessibleObject accessibleObject) { + static Boolean tryCanAccess(Object object, AccessibleObject accessibleObject) { + return tryCanAccess(canAccessMethodHandle, object, accessibleObject); + } + + static Boolean tryCanAccess(MethodHandle methodHandle, Object object, AccessibleObject accessibleObject) { Boolean access = null; - if (canAccessMethodHandle != null) { // JDK 9+ + if (methodHandle != null) { // JDK 9+ try { - access = (boolean) canAccessMethodHandle.invokeExact(accessibleObject, object); + access = (boolean) methodHandle.invokeExact(accessibleObject, object); } catch (Throwable e) { logger.error("It's failed to invokeExact on {} with object : {} , accessible object : {}", canAccessMethodHandle, object, accessibleObject, e); } @@ -189,7 +193,7 @@ private static Boolean tryCanAccess(Object object, AccessibleObject accessibleOb return access; } - private static void handleInaccessibleObjectExceptionIfFound(Throwable e) { + static void handleInaccessibleObjectExceptionIfFound(Throwable e) { if (isInaccessibleObjectException(e)) { String rawErrorMessage = e.getMessage(); String moduleName = substringBetween(rawErrorMessage, "module ", SPACE); diff --git a/microsphere-java-core/src/main/java/io/microsphere/reflect/ClassDefinition.java b/microsphere-java-core/src/main/java/io/microsphere/reflect/ClassDefinition.java index 2446c5e93..4a2bef849 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/reflect/ClassDefinition.java +++ b/microsphere-java-core/src/main/java/io/microsphere/reflect/ClassDefinition.java @@ -22,6 +22,8 @@ import io.microsphere.lang.Deprecation; import io.microsphere.util.Version; +import static java.util.Objects.nonNull; + /** * A concrete implementation of {@link ReflectiveDefinition} representing the definition of a Java class. * @@ -89,8 +91,7 @@ public ClassDefinition(@Nonnull Version since, @Nullable Deprecation deprecation } @Override - public final boolean isPresent() { - return super.getResolvedClass() != null; + public boolean isPresent() { + return nonNull(super.getResolvedClass()); } - -} +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/reflect/ExecutableDefinition.java b/microsphere-java-core/src/main/java/io/microsphere/reflect/ExecutableDefinition.java index f11401214..ce1aeab4b 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/reflect/ExecutableDefinition.java +++ b/microsphere-java-core/src/main/java/io/microsphere/reflect/ExecutableDefinition.java @@ -66,8 +66,6 @@ public abstract class ExecutableDefinition extends MemberD @Nonnull protected final String[] parameterClassNames; - private transient boolean resolvedParameterTypes; - @Nonnull private transient Class[] parameterTypes; @@ -137,17 +135,17 @@ public final String[] getParameterClassNames() { */ @Nonnull public final Class[] getParameterTypes() { - if (!this.resolvedParameterTypes && this.parameterTypes == null) { + if (this.parameterTypes == null) { this.parameterTypes = resolveParameterTypes(this.parameterClassNames); - this.resolvedParameterTypes = true; } return this.parameterTypes.clone(); } @Override public boolean equals(Object o) { - if (!(o instanceof ExecutableDefinition)) return false; - if (!super.equals(o)) return false; + if (!super.equals(o)) { + return false; + } ExecutableDefinition that = (ExecutableDefinition) o; return arrayEquals(this.parameterClassNames, that.parameterClassNames); diff --git a/microsphere-java-core/src/main/java/io/microsphere/reflect/FieldUtils.java b/microsphere-java-core/src/main/java/io/microsphere/reflect/FieldUtils.java index ec92e0425..fe139f1d3 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/reflect/FieldUtils.java +++ b/microsphere-java-core/src/main/java/io/microsphere/reflect/FieldUtils.java @@ -115,11 +115,7 @@ public static Field findField(Class klass, String fieldName) { // ignore, try the super class field = findField(klass.getSuperclass(), fieldName); } - if (field == null) { - if (logger.isTraceEnabled()) { - logger.trace("The field[name :'{}'] not found in class : '{}'", fieldName, klass); - } - } + logger.trace("To find the field[name :'{}'] from the class : '{}'", fieldName, klass); return field; } @@ -686,21 +682,17 @@ public static void assertFieldMatchType(Object instance, String fieldName, Class static void handleIllegalAccessException(IllegalAccessException e, Object instance, Field field, boolean accessible) { String errorMessage = format("The instance [object : {} , class : {} ] can't access the field[name : '{}' , type : {} , accessible : {}]", instance, getTypeName(instance.getClass()), field.getName(), getTypeName(field.getType()), accessible); - if (logger.isTraceEnabled()) { - logger.trace(errorMessage); - } + logger.trace(errorMessage); throw new IllegalStateException(errorMessage, e); } static void handleIllegalArgumentException(IllegalArgumentException e, Object instance, Field field) { String errorMessage = format("The instance[object : {} , class : {}] can't match the field[name : '{}' , type : {}]", instance, getTypeName(instance.getClass()), field.getName(), getTypeName(field.getType())); - if (logger.isTraceEnabled()) { - logger.trace(errorMessage); - } + logger.trace(errorMessage); throw new IllegalArgumentException(errorMessage, e); } private FieldUtils() { } -} +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/reflect/MemberDefinition.java b/microsphere-java-core/src/main/java/io/microsphere/reflect/MemberDefinition.java index 2d250a025..b837fe059 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/reflect/MemberDefinition.java +++ b/microsphere-java-core/src/main/java/io/microsphere/reflect/MemberDefinition.java @@ -25,6 +25,7 @@ import java.lang.reflect.Member; import static io.microsphere.util.Version.ofVersion; +import static java.util.Objects.nonNull; /** * The definition class for Java Reflection {@link Member}. @@ -81,8 +82,6 @@ public abstract class MemberDefinition extends ReflectiveDefin @Nullable private transient M member; - private boolean resolvedMember; - /** * @param since the 'since' version * @param declaredClassName the name of declared class @@ -166,22 +165,22 @@ public final Class getDeclaredClass() { */ @Nullable public final M getMember() { - if (!resolvedMember && member == null) { + if (member == null) { member = resolveMember(); - resolvedMember = true; } return member; } @Override public boolean isPresent() { - return getMember() != null; + return nonNull(getMember()); } @Override public boolean equals(Object o) { - if (!(o instanceof MemberDefinition)) return false; - if (!super.equals(o)) return false; + if (!super.equals(o)) { + return false; + } MemberDefinition that = (MemberDefinition) o; return this.name.equals(that.name); diff --git a/microsphere-java-core/src/main/java/io/microsphere/reflect/MultipleType.java b/microsphere-java-core/src/main/java/io/microsphere/reflect/MultipleType.java index 906a3198c..d4ae35a5a 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/reflect/MultipleType.java +++ b/microsphere-java-core/src/main/java/io/microsphere/reflect/MultipleType.java @@ -61,8 +61,12 @@ public int hashCode() { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + if (!(o instanceof MultipleType)) { + return false; + } MultipleType that = (MultipleType) o; return arrayEquals(types, that.types); } diff --git a/microsphere-java-core/src/main/java/io/microsphere/reflect/ReflectionUtils.java b/microsphere-java-core/src/main/java/io/microsphere/reflect/ReflectionUtils.java index f92cd2481..c675db165 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/reflect/ReflectionUtils.java +++ b/microsphere-java-core/src/main/java/io/microsphere/reflect/ReflectionUtils.java @@ -12,18 +12,21 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Objects; +import static io.microsphere.collection.MapUtils.newLinkedHashMap; import static io.microsphere.logging.LoggerFactory.getLogger; -import static io.microsphere.reflect.AccessibleObjectUtils.trySetAccessible; +import static io.microsphere.reflect.FieldUtils.getFieldValue; +import static io.microsphere.reflect.MemberUtils.isStatic; +import static io.microsphere.reflect.TypeUtils.getTypeName; import static io.microsphere.util.ClassLoaderUtils.resolveClass; +import static io.microsphere.util.ClassUtils.getType; import static io.microsphere.util.ClassUtils.isPrimitive; import static io.microsphere.util.ClassUtils.isSimpleType; import static java.lang.Class.forName; -import static java.lang.reflect.Modifier.isStatic; +import static java.lang.Thread.currentThread; +import static java.util.Collections.emptyMap; import static java.util.Collections.unmodifiableMap; /** @@ -128,7 +131,7 @@ public abstract class ReflectionUtils implements Utils { static { int invocationFrame = 0; // Use java.lang.StackTraceElement to calculate frame - StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); + StackTraceElement[] stackTraceElements = currentThread().getStackTrace(); for (StackTraceElement stackTraceElement : stackTraceElements) { String className = stackTraceElement.getClassName(); if (TYPE.getName().equals(className)) { @@ -217,7 +220,7 @@ static String getCallerClassNameInGeneralJVM() { * @return specified invocation frame class */ static String getCallerClassNameInGeneralJVM(int invocationFrame) throws IndexOutOfBoundsException { - StackTraceElement[] elements = Thread.currentThread().getStackTrace(); + StackTraceElement[] elements = currentThread().getStackTrace(); if (invocationFrame < elements.length) { StackTraceElement targetStackTraceElement = elements[invocationFrame]; return targetStackTraceElement.getClassName(); @@ -387,16 +390,14 @@ public static List toList(Object array) throws IllegalArgumentException { return list; } - private static Object toObject(Object object) { - if (object == null) { - return object; - } - Class type = object.getClass(); - if (type.isArray()) { - return toList(object); - } else { - return object; + static Object toObject(Object object) { + if (object != null) { + Class type = object.getClass(); + if (type.isArray()) { + return toList(object); + } } + return object; } @@ -445,31 +446,27 @@ private static Object toObject(Object object) { @Nonnull @Immutable public static Map readFieldsAsMap(Object object) { - Map fieldsAsMap = new LinkedHashMap(); + if (object == null) { + return emptyMap(); + } Class type = object.getClass(); Field[] fields = type.getDeclaredFields(); + Map fieldsAsMap = newLinkedHashMap(fields.length); for (Field field : fields) { - if (isStatic(field.getModifiers())) { // To filter static fields + if (isStatic(field)) { // To filter static fields continue; } - trySetAccessible(field); - - try { - String fieldName = field.getName(); - Object fieldValue = field.get(object); - if (fieldValue != null && fieldValue != object) { - Class fieldValueType = fieldValue.getClass(); - if (!isPrimitive(fieldValueType) - && !isSimpleType(fieldValueType) - && !Objects.equals(object.getClass(), fieldValueType)) { - fieldValue = readFieldsAsMap(fieldValue); - } - fieldsAsMap.put(fieldName, fieldValue); + String fieldName = field.getName(); + Object fieldValue = getFieldValue(object, field); + Class fieldValueType = field.getType(); + if (fieldValue != object) { + if (!isPrimitive(fieldValueType) && !isSimpleType(fieldValueType) + && !object.getClass().equals(fieldValueType)) { + fieldValue = readFieldsAsMap(fieldValue); } - } catch (IllegalAccessException e) { - throw new IllegalStateException(e); + fieldsAsMap.put(fieldName, fieldValue); } } return unmodifiableMap(fieldsAsMap); @@ -502,10 +499,39 @@ public static Map readFieldsAsMap(Object object) { * {@link java.lang.reflect.InaccessibleObjectException}, false otherwise. */ public static boolean isInaccessibleObjectException(Throwable failure) { - return failure != null && INACCESSIBLE_OBJECT_EXCEPTION_CLASS_NAME.equals(failure.getClass().getName()); + return isInaccessibleObjectException(getType(failure)); } - private ReflectionUtils() { + /** + * Checks whether the specified {@link Class} represents + * {@link java.lang.reflect.InaccessibleObjectException}. + * + *

    This method is useful when dealing with reflection operations that may fail due to module system + * restrictions introduced in JDK 9+. It avoids direct dependency on the presence of the class, which + * may not be available in earlier JDK versions.

    + * + *

    Example Usage

    + *
    {@code
    +     * Class exceptionClass = SomeException.class;
    +     * if (ReflectionUtils.isInaccessibleObjectException(exceptionClass)) {
    +     *     System.err.println("The class represents InaccessibleObjectException");
    +     * } else {
    +     *     System.out.println("The class does not represent InaccessibleObjectException");
    +     * }
    +     * }
    + * + * @param throwableClass The {@link Class} to check. + * @return true if the specified {@link Class} represents + * {@link java.lang.reflect.InaccessibleObjectException}, false otherwise. + */ + public static boolean isInaccessibleObjectException(Class throwableClass) { + return isInaccessibleObjectException(getTypeName(throwableClass)); } + static boolean isInaccessibleObjectException(String className) { + return INACCESSIBLE_OBJECT_EXCEPTION_CLASS_NAME.equals(className); + } + + private ReflectionUtils() { + } } \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/reflect/ReflectiveDefinition.java b/microsphere-java-core/src/main/java/io/microsphere/reflect/ReflectiveDefinition.java index abcf516f5..52fc3ba3b 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/reflect/ReflectiveDefinition.java +++ b/microsphere-java-core/src/main/java/io/microsphere/reflect/ReflectiveDefinition.java @@ -32,6 +32,7 @@ import static io.microsphere.util.ClassLoaderUtils.resolveClass; import static io.microsphere.util.Version.ofVersion; import static java.util.Objects.hash; +import static java.util.Objects.nonNull; /** * The abstract definition class for Java Reflection. @@ -101,8 +102,6 @@ public abstract class ReflectiveDefinition implements Serializable { @Nonnull protected final String className; - private transient boolean resolved; - @Nullable private transient Class resolvedClass; @@ -142,7 +141,6 @@ protected ReflectiveDefinition(@Nonnull Version since, @Nullable Deprecation dep this.since = since; this.deprecation = deprecation; this.className = className; - this.resolved = false; } /** @@ -182,10 +180,9 @@ public final String getClassName() { */ @Nullable public final Class getResolvedClass() { - if (!resolved && resolvedClass == null) { + if (resolvedClass == null) { ClassLoader classLoader = getClassLoader(getClass()); resolvedClass = resolveClass(className, classLoader, true); - resolved = true; } return resolvedClass; } @@ -194,7 +191,7 @@ public final Class getResolvedClass() { * Whether the member is deprecated */ public final boolean isDeprecated() { - return deprecation != null; + return nonNull(deprecation); } /** @@ -206,7 +203,13 @@ public final boolean isDeprecated() { @Override public boolean equals(Object o) { - if (!(o instanceof ReflectiveDefinition)) return false; + if (this == o) { + return true; + } + + if (!(this.getClass().isInstance(o))) { + return false; + } ReflectiveDefinition that = (ReflectiveDefinition) o; return this.since.equals(that.since) @@ -228,4 +231,4 @@ public String toString() { ", resolvedClass=" + this.getResolvedClass() + '}'; } -} +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/reflect/TypeUtils.java b/microsphere-java-core/src/main/java/io/microsphere/reflect/TypeUtils.java index e0b2a6e60..d105b4059 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/reflect/TypeUtils.java +++ b/microsphere-java-core/src/main/java/io/microsphere/reflect/TypeUtils.java @@ -646,7 +646,9 @@ static List doResolveActualTypeArgumentsInFastPath(Type type) { } @Nonnull - private static Map resolveTypeArgumentsMap(Type type, List hierarchicalTypes, int hierarchicalTypesSize, Class baseClass, TypeVariable[] baseTypeParameters) { + private static Map resolveTypeArgumentsMap(Type type, List hierarchicalTypes, + int hierarchicalTypesSize, Class baseClass, + TypeVariable[] baseTypeParameters) { int size = hierarchicalTypesSize + 1; @@ -663,14 +665,18 @@ private static Map resolveTypeArgumentsMap(Type type, Lis return typeArgumentsMap; } - private static void resolveTypeArgumentsMap(Type type, List hierarchicalTypes, int index, int hierarchicalTypesSize, Map typeArgumentsMap, Class baseClass, TypeVariable[] baseTypeParameters) { + private static void resolveTypeArgumentsMap(Type type, List hierarchicalTypes, int index, + int hierarchicalTypesSize, Map typeArgumentsMap, + Class baseClass, TypeVariable[] baseTypeParameters) { ParameterizedType pType = asParameterizedType(type); if (pType != null) { resolveTypeArgumentsMap(pType, hierarchicalTypes, index, hierarchicalTypesSize, typeArgumentsMap, baseClass, baseTypeParameters); } } - private static void resolveTypeArgumentsMap(ParameterizedType type, List hierarchicalTypes, int index, int hierarchicalTypesSize, Map typeArgumentsMap, Class baseClass, TypeVariable[] baseTypeParameters) { + private static void resolveTypeArgumentsMap(ParameterizedType type, List hierarchicalTypes, int index, + int hierarchicalTypesSize, Map typeArgumentsMap, + Class baseClass, TypeVariable[] baseTypeParameters) { Class klass = asClass(type); int baseTypeArgumentsLength = baseTypeParameters.length; @@ -1192,7 +1198,7 @@ public static List resolveTypeArguments(Class targetClass) { return emptyList(); } List typeArguments = newLinkedList(); - while (targetClass != null && targetClass != Object.class) { + while (targetClass != Object.class) { typeArguments.addAll(resolveTypeArguments(targetClass.getGenericSuperclass())); typeArguments.addAll(resolveTypeArguments(targetClass.getGenericInterfaces())); targetClass = targetClass.getSuperclass(); diff --git a/microsphere-java-core/src/main/java/io/microsphere/reflect/generics/TypeArgument.java b/microsphere-java-core/src/main/java/io/microsphere/reflect/generics/TypeArgument.java index b35669c00..1b1075fb6 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/reflect/generics/TypeArgument.java +++ b/microsphere-java-core/src/main/java/io/microsphere/reflect/generics/TypeArgument.java @@ -21,6 +21,7 @@ import static io.microsphere.util.Assert.assertNotNull; import static io.microsphere.util.Assert.assertTrue; +import static java.util.Objects.hash; /** * {@link Type} Argument @@ -59,20 +60,26 @@ public int getIndex() { @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) { + return true; + } + + if (!(o instanceof TypeArgument)) { + return false; + } TypeArgument that = (TypeArgument) o; - if (index != that.index) return false; + if (index != that.index) { + return false; + } + return Objects.equals(type, that.type); } @Override public int hashCode() { - int result = type != null ? type.hashCode() : 0; - result = 31 * result + index; - return result; + return hash(this.type, this.index); } diff --git a/microsphere-java-core/src/main/java/io/microsphere/util/Assert.java b/microsphere-java-core/src/main/java/io/microsphere/util/Assert.java index 362d81bad..262f56136 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/util/Assert.java +++ b/microsphere-java-core/src/main/java/io/microsphere/util/Assert.java @@ -502,4 +502,7 @@ public static void assertFieldMatchType(Object object, String fieldName, Class messageSupplier) { return messageSupplier == null ? null : messageSupplier.get(); } -} + + private Assert() { + } +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/util/ClassLoaderUtils.java b/microsphere-java-core/src/main/java/io/microsphere/util/ClassLoaderUtils.java index 78a6a4f80..4bb15f331 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/util/ClassLoaderUtils.java +++ b/microsphere-java-core/src/main/java/io/microsphere/util/ClassLoaderUtils.java @@ -562,7 +562,7 @@ protected static Class doLoadClass(ClassLoader classLoader, String className) if (isBlank(className)) { return null; } - Class klass = null; + Class klass; try { klass = classLoader.loadClass(className); } catch (Throwable e) { diff --git a/microsphere-java-core/src/main/java/io/microsphere/util/ClassPathUtils.java b/microsphere-java-core/src/main/java/io/microsphere/util/ClassPathUtils.java index debf3035d..a3a1c8784 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/util/ClassPathUtils.java +++ b/microsphere-java-core/src/main/java/io/microsphere/util/ClassPathUtils.java @@ -10,8 +10,6 @@ import java.lang.management.RuntimeMXBean; import java.net.URL; -import java.security.CodeSource; -import java.security.ProtectionDomain; import java.util.Set; import static io.microsphere.collection.SetUtils.ofSet; @@ -21,6 +19,7 @@ import static io.microsphere.util.ClassLoaderUtils.getDefaultClassLoader; import static io.microsphere.util.ClassLoaderUtils.isLoadedClass; import static io.microsphere.util.ClassLoaderUtils.resolveClass; +import static io.microsphere.util.ClassUtils.getCodeSourceLocation; import static io.microsphere.util.StringUtils.split; import static java.lang.ClassLoader.getSystemClassLoader; import static java.util.Collections.emptySet; @@ -189,13 +188,7 @@ public static URL getRuntimeClassLocation(Class type) { ClassLoader classLoader = type.getClassLoader(); URL location = null; if (classLoader != null) { // Non-Bootstrap - try { - ProtectionDomain protectionDomain = type.getProtectionDomain(); - CodeSource codeSource = protectionDomain.getCodeSource(); - location = codeSource == null ? null : codeSource.getLocation(); - } catch (SecurityException exception) { - - } + location = getCodeSourceLocation(type); } else if (!type.isPrimitive() && !type.isArray() && !type.isSynthetic()) { // Bootstrap ClassLoader // Class was loaded by Bootstrap ClassLoader location = getClassResource(getSystemClassLoader(), type.getName()); @@ -206,4 +199,4 @@ public static URL getRuntimeClassLocation(Class type) { private ClassPathUtils() { } -} +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/util/ClassUtils.java b/microsphere-java-core/src/main/java/io/microsphere/util/ClassUtils.java index 35a2beb27..53a1430bf 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/util/ClassUtils.java +++ b/microsphere-java-core/src/main/java/io/microsphere/util/ClassUtils.java @@ -7,6 +7,7 @@ import io.microsphere.annotation.Nonnull; import io.microsphere.annotation.Nullable; import io.microsphere.filter.ClassFileJarEntryFilter; +import io.microsphere.io.FileUtils; import io.microsphere.io.filter.FileExtensionFilter; import io.microsphere.io.filter.IOFileFilter; import io.microsphere.io.scanner.SimpleFileScanner; @@ -18,6 +19,9 @@ import java.lang.reflect.Modifier; import java.math.BigDecimal; import java.math.BigInteger; +import java.net.URL; +import java.security.CodeSource; +import java.security.ProtectionDomain; import java.util.Date; import java.util.LinkedHashSet; import java.util.List; @@ -30,6 +34,7 @@ import java.util.jar.JarFile; import static io.microsphere.collection.CollectionUtils.isEmpty; +import static io.microsphere.collection.CollectionUtils.size; import static io.microsphere.collection.MapUtils.newFixedLinkedHashMap; import static io.microsphere.collection.SetUtils.newFixedLinkedHashSet; import static io.microsphere.collection.SetUtils.newLinkedHashSet; @@ -39,6 +44,7 @@ import static io.microsphere.constants.FileConstants.JAR_EXTENSION; import static io.microsphere.constants.PathConstants.SLASH; import static io.microsphere.constants.ProtocolConstants.FILE_PROTOCOL; +import static io.microsphere.constants.ProtocolConstants.JAR_PROTOCOL; import static io.microsphere.constants.SeparatorConstants.ARCHIVE_ENTRY_SEPARATOR; import static io.microsphere.constants.SymbolConstants.COLON_CHAR; import static io.microsphere.constants.SymbolConstants.DOLLAR_CHAR; @@ -1059,12 +1065,19 @@ public static String resolvePackageName(@Nullable String className) { @Immutable public static Set findClassNamesInClassPath(@Nullable String classPath, boolean recursive) { String protocol = resolveProtocol(classPath); - final String resolvedClassPath; - if (FILE_PROTOCOL.equals(protocol)) { + String resolvedClassPath = classPath; + + if (JAR_PROTOCOL.equals(protocol)) { + String path = substringAfter(classPath, protocol + COLON_CHAR); + return findClassNamesInClassPath(path, recursive); + } else if (FILE_PROTOCOL.equals(protocol)) { + String prefix = protocol + COLON_CHAR; resolvedClassPath = substringBetween(classPath, protocol + COLON_CHAR, ARCHIVE_ENTRY_SEPARATOR); - } else { - resolvedClassPath = classPath; + if (resolvedClassPath == null) { + resolvedClassPath = substringAfter(classPath, prefix); + } } + File classesFileHolder = new File(resolvedClassPath); // File or Directory return findClassNamesInClassPath(classesFileHolder, recursive); } @@ -1102,17 +1115,12 @@ public static Set findClassNamesInClassPath(@Nullable File classPath, bo Set classNames = emptySet(); if (classPath.isDirectory()) { // Directory classNames = findClassNamesInDirectory(classPath, recursive); - } else if (classPath.isFile()) { // File - if (JAR_FILE_EXTENSION_FILTER.accept(classPath)) { // JarFile - classNames = findClassNamesInJarFile(classPath, recursive); - } + } else if (JAR_FILE_EXTENSION_FILTER.accept(classPath)) { // JarFile + classNames = findClassNamesInJarFile(classPath, recursive); } - if (isEmpty(classNames)) { - if (logger.isTraceEnabled()) { - logger.trace("No Class was found in the classPath : '{}' , recursive : {}", classPath, recursive); - } - } + logger.trace("To find the class names in the class path['{}' , recursive : {}] : {}", classPath, recursive, classNames); + return classNames; } @@ -1194,10 +1202,11 @@ public static Set findClassNamesInJarFile(@Nullable File jarFile, boolea try { JarFile jarFile_ = new JarFile(jarFile); Set jarEntries = INSTANCE.scan(jarFile_, recursive, ClassFileJarEntryFilter.INSTANCE); - if (isEmpty(jarEntries)) { + int size = size(jarEntries); + if (size == 0) { classNames = emptySet(); } else { - classNames = newLinkedHashSet(); + classNames = newLinkedHashSet(size); for (JarEntry jarEntry : jarEntries) { String jarEntryName = jarEntry.getName(); String className = resolveClassName(jarEntryName); @@ -1209,10 +1218,8 @@ public static Set findClassNamesInJarFile(@Nullable File jarFile, boolea } } catch (Exception e) { classNames = emptySet(); - if (logger.isTraceEnabled()) { - logger.trace("The class names can't be resolved by SimpleJarEntryScanner#scan(jarFile = {} ," + - " recursive = {} , jarEntryFilter = ClassFileJarEntryFilter)", jarFile, recursive, e); - } + logger.trace("The class names can't be resolved by SimpleJarEntryScanner#scan(jarFile = {} ," + + " recursive = {} , jarEntryFilter = ClassFileJarEntryFilter)", jarFile, recursive, e); } return classNames; } @@ -1236,7 +1243,7 @@ public static Set findClassNamesInJarFile(@Nullable File jarFile, boolea * @param classesDirectory the root directory containing compiled classes, must not be {@code null} * @param classFile the class file to resolve the name for, must not be {@code null} * @return the fully qualified class name, never {@code null} - * @see #resolveRelativePath(File, File) + * @see FileUtils#resolveRelativePath(File, File) * @see #resolveClassName(String) */ protected static String resolveClassName(File classesDirectory, File classFile) { @@ -1711,7 +1718,10 @@ public static Class getType(@Nullable Object value) { */ @Nullable public static Class getClass(@Nullable Object object) { - return object == null ? null : object.getClass(); + if (object == null) { + return null; + } + return object instanceof Class ? (Class) object : object.getClass(); } /** @@ -1801,22 +1811,19 @@ public static String getTypeName(@Nullable Class type) { return null; } if (type.isArray()) { - try { - Class cl = type; - int dimensions = 0; - while (cl.isArray()) { - dimensions++; - cl = cl.getComponentType(); - } - String name = getTypeName(cl); - StringBuilder sb = new StringBuilder(name.length() + dimensions * 2); - sb.append(name); - for (int i = 0; i < dimensions; i++) { - sb.append("[]"); - } - return sb.toString(); - } catch (Throwable e) { + Class cl = type; + int dimensions = 0; + while (cl.isArray()) { + dimensions++; + cl = cl.getComponentType(); + } + String name = getTypeName(cl); + StringBuilder sb = new StringBuilder(name.length() + dimensions * 2); + sb.append(name); + for (int i = 0; i < dimensions; i++) { + sb.append("[]"); } + return sb.toString(); } return type.getName(); } @@ -1859,7 +1866,11 @@ private static String getSimpleName(Class type, boolean array) { if (array) { return getSimpleName(type.getComponentType()) + "[]"; } - String simpleName = type.getName(); + return getSimpleName(type, type.getName()); + } + + static String getSimpleName(Class type, String className) { + String simpleName = className; Class enclosingClass = type.getEnclosingClass(); if (enclosingClass == null) { // top level class simpleName = simpleName.substring(simpleName.lastIndexOf(DOT_CHAR) + 1); @@ -1868,16 +1879,20 @@ private static String getSimpleName(Class type, boolean array) { simpleName = simpleName.substring(ecName.length()); // Remove leading "\$[0-9]*" from the name int length = simpleName.length(); - if (length < 1 || simpleName.charAt(0) != DOLLAR_CHAR) throw new InternalError("Malformed class name"); + if (length < 1 || simpleName.charAt(0) != DOLLAR_CHAR) { + throw new InternalError("Malformed class name"); + } int index = 1; - while (index < length && isAsciiDigit(simpleName.charAt(index))) index++; + while (index < length && isAsciiDigit(simpleName.charAt(index))) { + index++; + } // Eventually, this is the empty string iff this is an anonymous class return simpleName.substring(index); } return simpleName; } - private static boolean isAsciiDigit(char c) { + static boolean isAsciiDigit(char c) { return '0' <= c && c <= '9'; } @@ -2126,7 +2141,93 @@ public static T cast(@Nullable Object object, @Nullable Class castType) { return castType.isInstance(object) ? castType.cast(object) : null; } - private ClassUtils() { + /** + * Gets the protection domain of the specified class. + *

    + * This method returns the {@link ProtectionDomain} of the given class. + * The protection domain encapsulates the security information associated + * with the class, such as the code source and permissions. If the class + * is {@code null}, this method returns {@code null}. + *

    + * + *

    Example Usage

    + *
    {@code
    +     * ProtectionDomain pd = ClassUtils.getProtectionDomain(String.class);
    +     * // Returns the protection domain of the String class
    +     *
    +     * ProtectionDomain nullPd = ClassUtils.getProtectionDomain(null);
    +     * // Returns null since the input class is null
    +     * }
    + * + * @param type the class to get the protection domain from, may be {@code null} + * @return the protection domain of the specified class, or {@code null} if the class is {@code null} + * @see Class#getProtectionDomain() + */ + @Nullable + public static ProtectionDomain getProtectionDomain(@Nullable Class type) { + return type == null ? null : type.getProtectionDomain(); } -} + /** + * Gets the code source of the specified class. + *

    + * This method returns the {@link CodeSource} of the given class. + * The code source represents the location (URL) from which the class was loaded, + * along with the certificates associated with the code. If the class is {@code null} + * or if the protection domain of the class is {@code null}, this method returns {@code null}. + *

    + * + *

    Example Usage

    + *
    {@code
    +     * CodeSource codeSource = ClassUtils.getCodeSource(String.class);
    +     * // Returns the code source of the String class
    +     *
    +     * CodeSource nullCodeSource = ClassUtils.getCodeSource(null);
    +     * // Returns null since the input class is null
    +     * }
    + * + * @param type the class to get the code source from, may be {@code null} + * @return the code source of the specified class, or {@code null} if the class is {@code null} + * or if the protection domain is {@code null} + * @see ProtectionDomain#getCodeSource() + * @see Class#getProtectionDomain() + */ + @Nullable + public static CodeSource getCodeSource(@Nullable Class type) { + ProtectionDomain protectionDomain = getProtectionDomain(type); + return protectionDomain == null ? null : protectionDomain.getCodeSource(); + } + + /** + * Gets the code source location of the specified class. + *

    + * This method returns the location (URL) from which the given class was loaded. + * The location is obtained from the {@link CodeSource} associated with the class's + * {@link ProtectionDomain}. If the class is {@code null}, or if the protection domain + * or code source is {@code null}, this method returns {@code null}. + *

    + * + *

    Example Usage

    + *
    {@code
    +     * URL location = ClassUtils.getCodeSourceLocation(String.class);
    +     * // Returns the URL location from which the String class was loaded
    +     *
    +     * URL nullLocation = ClassUtils.getCodeSourceLocation(null);
    +     * // Returns null since the input class is null
    +     * }
    + * + * @param type the class to get the code source location from, may be {@code null} + * @return the code source location of the specified class, or {@code null} if the class is {@code null}, + * or if the protection domain or code source is {@code null} + * @see CodeSource#getLocation() + * @see Class#getProtectionDomain() + */ + @Nullable + public static URL getCodeSourceLocation(@Nullable Class type) { + CodeSource codeSource = getCodeSource(type); + return codeSource == null ? null : codeSource.getLocation(); + } + + private ClassUtils() { + } +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/util/PriorityComparator.java b/microsphere-java-core/src/main/java/io/microsphere/util/PriorityComparator.java index 6b7c6d062..f0ab08fdd 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/util/PriorityComparator.java +++ b/microsphere-java-core/src/main/java/io/microsphere/util/PriorityComparator.java @@ -16,12 +16,14 @@ */ package io.microsphere.util; +import java.lang.annotation.Annotation; import java.util.Comparator; import java.util.Objects; import static io.microsphere.reflect.MethodUtils.invokeMethod; import static io.microsphere.util.AnnotationUtils.findAnnotation; import static io.microsphere.util.ClassLoaderUtils.resolveClass; +import static io.microsphere.util.ClassUtils.getType; /** * A {@link Comparator} implementation that sorts objects based on the value of the @@ -59,16 +61,20 @@ public class PriorityComparator implements Comparator { @Override public int compare(Object o1, Object o2) { - return compare(asClass(o1), asClass(o2)); + return compare(getType(o1), getType(o2)); } - public static int compare(Class type1, Class type2) { - if (Objects.equals(type1, type2) || PRIORITY_CLASS == null) { + static int compare(Class type1, Class type2) { + return compare(type1, type2, PRIORITY_CLASS); + } + + static int compare(Class type1, Class type2, Class priorityClass) { + if (Objects.equals(type1, type2) || priorityClass == null) { return 0; } - Object priority1 = findAnnotation(type1, PRIORITY_CLASS); - Object priority2 = findAnnotation(type2, PRIORITY_CLASS); + Object priority1 = findAnnotation(type1, priorityClass); + Object priority2 = findAnnotation(type2, priorityClass); int priorityValue1 = getValue(priority1); int priorityValue2 = getValue(priority2); @@ -76,13 +82,8 @@ public static int compare(Class type1, Class type2) { return Integer.compare(priorityValue1, priorityValue2); } - private static Class asClass(Object object) { - return object instanceof Class ? (Class) object : object.getClass(); - } - - private static int getValue(Object priority) { + static int getValue(Object priority) { int value = priority == null ? UNDEFINED_VALUE : invokeMethod(priority, "value"); return value < 0 ? UNDEFINED_VALUE : value; } - -} +} \ No newline at end of file diff --git a/microsphere-java-core/src/main/java/io/microsphere/util/StringUtils.java b/microsphere-java-core/src/main/java/io/microsphere/util/StringUtils.java index b8e92bf57..f5e8da389 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/util/StringUtils.java +++ b/microsphere-java-core/src/main/java/io/microsphere/util/StringUtils.java @@ -173,7 +173,7 @@ public static String[] split(@Nullable String value, @Nullable String delimiter) List result = new ArrayList<>(); if (delimiterLength == 0) { - for (int i = 0; i < value.length(); i++) { + for (int i = 0; i < length; i++) { result.add(value.substring(i, i + 1)); } } else { @@ -882,6 +882,5 @@ static String trimWhitespace(String str, boolean includeLeading, boolean include } private StringUtils() { - super(); } -} +} \ No newline at end of file diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/ArrayTypeModel.java b/microsphere-java-core/src/main/java/io/microsphere/util/ThrowableUtils.java similarity index 62% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/ArrayTypeModel.java rename to microsphere-java-core/src/main/java/io/microsphere/util/ThrowableUtils.java index fc6c057f3..8f6d32c23 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/ArrayTypeModel.java +++ b/microsphere-java-core/src/main/java/io/microsphere/util/ThrowableUtils.java @@ -14,23 +14,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor.model; + +package io.microsphere.util; /** - * Array Type Model + * The uitlities class for {@link Throwable} * + * @author Mercy + * @see Throwable * @since 1.0.0 */ -public class ArrayTypeModel { - - private int[] integers; // Primitive type array - - private String[] strings; // Simple type array - - private PrimitiveTypeModel[] primitiveTypeModels; // Complex type array +public abstract class ThrowableUtils implements Utils { - private Model[] models; // Hierarchical Complex type array + public static Throwable getRootCause(Throwable throwable) { + Throwable rootCause = throwable; + while (rootCause.getCause() != null) { + rootCause = rootCause.getCause(); + } + return rootCause; + } - private Color[] colors; // Enum type array + private ThrowableUtils() { + } } diff --git a/microsphere-java-core/src/main/java/io/microsphere/util/Version.java b/microsphere-java-core/src/main/java/io/microsphere/util/Version.java index 648702314..a1833ee54 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/util/Version.java +++ b/microsphere-java-core/src/main/java/io/microsphere/util/Version.java @@ -19,7 +19,6 @@ import io.microsphere.annotation.Immutable; import io.microsphere.annotation.Nonnull; import io.microsphere.annotation.Nullable; -import io.microsphere.lang.ClassDataRepository; import java.io.Serializable; import java.net.URL; @@ -36,11 +35,11 @@ import static io.microsphere.constants.SymbolConstants.LESS_THAN_OR_EQUAL_TO; import static io.microsphere.constants.SymbolConstants.QUOTE_CHAR; import static io.microsphere.constants.SymbolConstants.SPACE_CHAR; -import static io.microsphere.lang.ClassDataRepository.INSTANCE; import static io.microsphere.text.FormatUtils.format; import static io.microsphere.util.Assert.assertNotBlank; import static io.microsphere.util.Assert.assertNotNull; import static io.microsphere.util.Assert.assertTrue; +import static io.microsphere.util.ClassUtils.getCodeSourceLocation; import static io.microsphere.util.StringUtils.split; import static io.microsphere.util.Version.Operator.EQ; import static io.microsphere.util.Version.Operator.GE; @@ -404,8 +403,7 @@ public static Version getVersion(Class targetClass) throws IllegalArgumentExc Package targetPackage = targetClass.getPackage(); String version = targetPackage.getImplementationVersion(); if (version == null) { - ClassDataRepository repository = INSTANCE; - URL classResource = repository.getCodeSourceLocation(targetClass); + URL classResource = getCodeSourceLocation(targetClass); String errorMessage = format("The 'Implementation-Version' manifest attribute can't be fetched from the jar file[class resource : '{}'] by the target class[name :'{}']", classResource, targetClass.getName()); throw new IllegalArgumentException(errorMessage); } diff --git a/microsphere-java-core/src/main/java/io/microsphere/util/jar/JarUtils.java b/microsphere-java-core/src/main/java/io/microsphere/util/jar/JarUtils.java index a36ab6787..0fd1a9d73 100644 --- a/microsphere-java-core/src/main/java/io/microsphere/util/jar/JarUtils.java +++ b/microsphere-java-core/src/main/java/io/microsphere/util/jar/JarUtils.java @@ -8,6 +8,8 @@ import io.microsphere.annotation.Nullable; import io.microsphere.constants.ProtocolConstants; import io.microsphere.filter.JarEntryFilter; +import io.microsphere.logging.Logger; +import io.microsphere.net.URLUtils; import io.microsphere.util.Utils; import java.io.File; @@ -16,22 +18,26 @@ import java.io.InputStream; import java.io.OutputStream; import java.net.URL; +import java.util.Collection; import java.util.Enumeration; import java.util.LinkedList; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; +import static io.microsphere.collection.CollectionUtils.isEmpty; import static io.microsphere.collection.ListUtils.ofList; import static io.microsphere.constants.ProtocolConstants.FILE_PROTOCOL; import static io.microsphere.constants.ProtocolConstants.JAR_PROTOCOL; import static io.microsphere.constants.SeparatorConstants.ARCHIVE_ENTRY_SEPARATOR; import static io.microsphere.io.IOUtils.close; import static io.microsphere.io.IOUtils.copy; +import static io.microsphere.logging.LoggerFactory.getLogger; import static io.microsphere.net.URLUtils.decode; import static io.microsphere.net.URLUtils.normalizePath; import static io.microsphere.net.URLUtils.resolveArchiveFile; import static io.microsphere.text.FormatUtils.format; +import static io.microsphere.util.StringUtils.EMPTY; import static io.microsphere.util.StringUtils.substringAfter; import static java.util.Collections.emptyList; import static java.util.Collections.unmodifiableList; @@ -46,6 +52,8 @@ */ public abstract class JarUtils implements Utils { + private static final Logger logger = getLogger(URLUtils.class); + /** * The resource path of Manifest file in JAR archive. * Typically located under {@code META-INF/MANIFEST.MF} in standard Java archives. @@ -69,15 +77,20 @@ public abstract class JarUtils implements Utils { * * @param jarURL the URL pointing to a JAR file or entry; must not be {@code null} * @return a new {@link JarFile} instance if resolved successfully, or {@code null} if resolution fails - * @throws IOException if an I/O error occurs while creating the JAR file + * @throws IllegalArgumentException if the URL protocol is neither "jar" nor "file" */ @Nullable - public static JarFile toJarFile(URL jarURL) throws IOException { - JarFile jarFile = null; + public static JarFile toJarFile(URL jarURL) throws IllegalArgumentException { final String jarAbsolutePath = resolveJarAbsolutePath(jarURL); - if (jarAbsolutePath == null) + if (jarAbsolutePath == null) { return null; - jarFile = new JarFile(jarAbsolutePath); + } + JarFile jarFile = null; + try { + jarFile = new JarFile(jarAbsolutePath); + } catch (IOException e) { + logger.trace("The JarFile can't be open from the url : {}", jarURL, e); + } return jarFile; } @@ -211,11 +224,13 @@ protected static List doFilter(Iterable jarEntries, JarEntry * * @param jarURL the URL pointing to a resource within a JAR file; must not be {@code null} * @return the resolved {@link JarEntry} if found, or {@code null} if no such entry exists - * @throws IOException if an I/O error occurs while reading the JAR file or resolving the entry */ @Nullable - public static JarEntry findJarEntry(URL jarURL) throws IOException { + public static JarEntry findJarEntry(URL jarURL) { JarFile jarFile = toJarFile(jarURL); + if (jarFile == null) { + return null; + } final String relativePath = resolveRelativePath(jarURL); JarEntry jarEntry = jarFile.getJarEntry(relativePath); return jarEntry; @@ -341,14 +356,11 @@ public static void extract(URL jarResourceURL, File targetDirectory, JarEntryFil final String relativePath = resolveRelativePath(jarResourceURL); final JarEntry jarEntry = jarFile.getJarEntry(relativePath); final boolean isDirectory = jarEntry.isDirectory(); - List jarEntriesList = filter(jarFile, new JarEntryFilter() { - @Override - public boolean accept(JarEntry filteredObject) { - String name = filteredObject.getName(); - if (isDirectory && name.equals(relativePath)) { - return true; - } else return name.startsWith(relativePath); - } + List jarEntriesList = filter(jarFile, entry -> { + String name = entry.getName(); + if (isDirectory && name.equals(relativePath)) { + return true; + } else return name.startsWith(relativePath); }); jarEntriesList = doFilter(jarEntriesList, jarEntryFilter); @@ -356,30 +368,75 @@ public boolean accept(JarEntry filteredObject) { doExtract(jarFile, jarEntriesList, targetDirectory); } - protected static void doExtract(JarFile jarFile, Iterable jarEntries, File targetDirectory) throws IOException { - if (jarEntries != null) { - for (JarEntry jarEntry : jarEntries) { - String jarEntryName = jarEntry.getName(); - File targetFile = new File(targetDirectory, jarEntryName); - if (jarEntry.isDirectory()) { - targetFile.mkdirs(); - } else { - InputStream inputStream = null; - OutputStream outputStream = null; - try { - inputStream = jarFile.getInputStream(jarEntry); - if (inputStream != null) { - File parentFile = targetFile.getParentFile(); - if (!parentFile.exists()) { - parentFile.mkdirs(); - } - outputStream = new FileOutputStream(targetFile); - copy(inputStream, outputStream); + + /** + * Determines whether the specified URL points to a directory entry within a JAR file. + * + *

    + * This method checks if the given URL represents a directory entry in a JAR archive. + * It supports only the "jar" protocol. For URLs with the "jar" protocol, it resolves + * the JAR file and verifies if the relative path corresponds to a directory entry. + * If the relative path is empty, it is treated as the root directory of the JAR. + *

    + * + *

    Example Usage

    + *
    {@code
    +     * URL jarURL = new URL("jar:file:/path/to/file.jar!/");
    +     * boolean isDirectory = JarUtils.isDirectoryEntry(jarURL);
    +     * System.out.println(isDirectory);  // Output: true
    +     *
    +     * URL fileURL = new URL("jar:file:/path/to/file.jar!/com/example/");
    +     * isDirectory = JarUtils.isDirectoryEntry(fileURL);
    +     * System.out.println(isDirectory);  // Output: true
    +     *
    +     * URL resourceURL = new URL("jar:file:/path/to/file.jar!/com/example/resource.txt");
    +     * isDirectory = JarUtils.isDirectoryEntry(resourceURL);
    +     * System.out.println(isDirectory);  // Output: false
    +     * }
    + * + * @param url the URL to check; must not be {@code null} + * @return {@code true} if the URL points to a directory entry in a JAR file, {@code false} otherwise + * @throws IOException if an I/O error occurs while resolving the JAR file or entry + */ + public static boolean isDirectoryEntry(URL url) { + String protocol = url.getProtocol(); + if (JAR_PROTOCOL.equals(protocol)) { + final String relativePath = resolveRelativePath(url); + if (EMPTY.equals(relativePath)) { // root directory in jar + return true; + } else { + JarEntry jarEntry = findJarEntry(url); + return jarEntry != null && jarEntry.isDirectory(); + } + } + return false; + } + + protected static void doExtract(JarFile jarFile, Collection jarEntries, File targetDirectory) throws IOException { + if (jarFile == null || isEmpty(jarEntries)) { + return; + } + for (JarEntry jarEntry : jarEntries) { + String jarEntryName = jarEntry.getName(); + File targetFile = new File(targetDirectory, jarEntryName); + if (jarEntry.isDirectory()) { + targetFile.mkdirs(); + } else { + InputStream inputStream = null; + OutputStream outputStream = null; + try { + inputStream = jarFile.getInputStream(jarEntry); + if (inputStream != null) { + File parentFile = targetFile.getParentFile(); + if (!parentFile.exists()) { + parentFile.mkdirs(); } - } finally { - close(outputStream); - close(inputStream); + outputStream = new FileOutputStream(targetFile); + copy(inputStream, outputStream); } + } finally { + close(outputStream); + close(inputStream); } } } @@ -387,5 +444,4 @@ protected static void doExtract(JarFile jarFile, Iterable jarEntries, private JarUtils() { } - -} +} \ No newline at end of file diff --git a/microsphere-java-core/src/test/java/io/microsphere/AbstractTestCase.java b/microsphere-java-core/src/test/java/io/microsphere/AbstractTestCase.java index 154b18633..c9be0e306 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/AbstractTestCase.java +++ b/microsphere-java-core/src/test/java/io/microsphere/AbstractTestCase.java @@ -5,6 +5,7 @@ import io.microsphere.lang.function.ThrowableAction; import io.microsphere.logging.Logger; +import io.microsphere.process.ProcessExecutor; import org.junit.jupiter.api.Disabled; import java.io.File; @@ -19,7 +20,6 @@ import java.util.List; import java.util.Queue; import java.util.Set; -import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; import java.util.function.Consumer; @@ -32,12 +32,14 @@ import static io.microsphere.management.JmxUtils.getRuntimeMXBean; import static io.microsphere.reflect.TypeUtils.asClass; import static io.microsphere.util.ClassLoaderUtils.getClassLoader; +import static io.microsphere.util.SystemUtils.IS_OS_WINDOWS; import static io.microsphere.util.SystemUtils.JAVA_IO_TMPDIR; import static java.lang.String.valueOf; import static java.util.Collections.emptyList; import static java.util.Collections.emptySet; import static java.util.Collections.singleton; import static java.util.Collections.singletonList; +import static java.util.UUID.randomUUID; import static java.util.concurrent.ThreadLocalRandom.current; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -126,56 +128,68 @@ public abstract class AbstractTestCase { protected final Logger logger = getLogger(getClass()); - public void log(Object object) { + protected void log(Object object) { if (logger.isTraceEnabled()) { logger.trace(valueOf(object)); } } - public void log(String object, Object... args) { + protected void log(String object, Object... args) { if (logger.isTraceEnabled()) { logger.trace(object, args); } } protected File createRandomTempDirectory() { - File tempDir = newTempFile(buildRandomFileName()); - assertTrue(tempDir.mkdir()); - return tempDir; + return createRandomDirectory(TEST_TEMP_DIR); + } + + protected File createRandomTempFile() throws IOException { + return createRandomFile(TEST_TEMP_DIR); + } + + protected File newRandomTempFile() { + return newRandomFile(TEST_TEMP_DIR); } protected File createRandomDirectory(File parentDir) { File tempDir = newRandomFile(parentDir); assertTrue(tempDir.mkdir()); + tempDir.deleteOnExit(); return tempDir; } - protected File createRandomTempFile() throws IOException { - File randomTempFile = newRandomTempFile(); - assertTrue(randomTempFile.createNewFile()); - return randomTempFile; - } - protected File createRandomFile(File parentDir) throws IOException { File randomFile = newRandomFile(parentDir); assertTrue(randomFile.createNewFile()); + randomFile.deleteOnExit(); return randomFile; } - protected File newRandomTempFile() { - return newTempFile(buildRandomFileName()); - } - protected File newRandomFile(File parentDir) { return new File(parentDir, buildRandomFileName()); } protected String buildRandomFileName() { - return UUID.randomUUID().toString(); + return randomUUID().toString(); } - protected File newTempFile(String path) { - return new File(TEST_TEMP_DIR, path); + protected File makeLinkFile(File targetFile) throws Exception { + File tempDir = createRandomTempDirectory(); + File linkFile = new File(tempDir, "link"); + boolean directory = targetFile.isDirectory(); + String targetPatth = targetFile.getAbsolutePath(); + String linkPath = linkFile.getAbsolutePath(); + final ProcessExecutor processExecutor; + if (IS_OS_WINDOWS) { + processExecutor = directory ? + new ProcessExecutor("mklink", "/D", targetPatth, linkPath) : + new ProcessExecutor("mklink", targetPatth, linkPath); + } else { + processExecutor = new ProcessExecutor("ln", "-s", targetPatth, linkPath); + } + processExecutor.execute(System.out); + return linkFile; } protected void assertThrowable(ThrowableAction action, Consumer failureHandler) { diff --git a/microsphere-java-core/src/test/java/io/microsphere/classloading/BannedArtifactClassLoadingExecutorTest.java b/microsphere-java-core/src/test/java/io/microsphere/classloading/BannedArtifactClassLoadingExecutorTest.java index f5e15dff7..f94a96960 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/classloading/BannedArtifactClassLoadingExecutorTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/classloading/BannedArtifactClassLoadingExecutorTest.java @@ -18,6 +18,15 @@ import org.junit.jupiter.api.Test; +import java.io.IOException; +import java.net.URL; +import java.util.Enumeration; + +import static io.microsphere.classloading.BannedArtifactClassLoadingExecutor.loadBannedArtifactConfig; +import static io.microsphere.classloading.BannedArtifactClassLoadingExecutor.loadBannedArtifactConfigs; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + /** * {@link BannedArtifactClassLoadingExecutor} Test * @@ -26,10 +35,25 @@ */ class BannedArtifactClassLoadingExecutorTest { - private BannedArtifactClassLoadingExecutor detector = new BannedArtifactClassLoadingExecutor(); - @Test void testDetect() { + BannedArtifactClassLoadingExecutor detector = new BannedArtifactClassLoadingExecutor(); detector.execute(); } -} + + @Test + void testLoadBannedArtifactConfigsOnFailed() { + ClassLoader classLoader = new ClassLoader() { + @Override + public Enumeration getResources(String name) throws IOException { + throw new IOException("For testing"); + } + }; + assertTrue(loadBannedArtifactConfigs(classLoader).isEmpty()); + } + + @Test + void testLoadBannedArtifactConfigOnFailed() { + assertThrows(IllegalArgumentException.class, () -> loadBannedArtifactConfig("invalid-definition")); + } +} \ No newline at end of file diff --git a/microsphere-java-core/src/test/java/io/microsphere/classloading/ManifestArtifactResourceResolverTest.java b/microsphere-java-core/src/test/java/io/microsphere/classloading/ManifestArtifactResourceResolverTest.java index 882363396..91edaf153 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/classloading/ManifestArtifactResourceResolverTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/classloading/ManifestArtifactResourceResolverTest.java @@ -1,6 +1,11 @@ package io.microsphere.classloading; +import org.junit.jupiter.api.Test; + +import java.util.jar.Manifest; + import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; /** * {@link ManifestArtifactResourceResolver} Test @@ -16,4 +21,12 @@ void assertArtifact(Artifact artifact) { assertEquals("FindBugs-jsr305", artifact.getArtifactId()); assertEquals(TEST_VERSION, artifact.getVersion()); } + + @Test + void testresolveArtifactMetaInfoInManifestOnNotFound() { + ManifestArtifactResourceResolver resolver = this.resolver; + Manifest manifest = new Manifest(); + Artifact artifact = resolver.resolveArtifactMetaInfoInManifest(manifest, null); + assertNull(artifact); + } } \ No newline at end of file diff --git a/microsphere-java-core/src/test/java/io/microsphere/classloading/ServiceLoadingURLClassPathHandleTest.java b/microsphere-java-core/src/test/java/io/microsphere/classloading/ServiceLoadingURLClassPathHandleTest.java index 09261ba82..82a41f39e 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/classloading/ServiceLoadingURLClassPathHandleTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/classloading/ServiceLoadingURLClassPathHandleTest.java @@ -19,12 +19,13 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; +import static io.microsphere.net.URLUtils.EMPTY_URL_ARRAY; import static io.microsphere.util.ClassLoaderUtils.getDefaultClassLoader; import static io.microsphere.util.ClassLoaderUtils.newURLClassLoader; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -44,16 +45,26 @@ void setUp() { } @Test - void test() throws IOException { - ServiceLoadingURLClassPathHandle handle = new ServiceLoadingURLClassPathHandle(); - assertTrue(handle.supports()); + void testSupports() { + assertTrue(this.handle.supports()); + } + + @Test + void testGetURLs() { ClassLoader classLoader = getDefaultClassLoader(); URL[] urls = handle.getURLs(classLoader); assertNotNull(urls); + assertArrayEquals(EMPTY_URL_ARRAY, handle.getURLs(null)); + } + + @Test + void testRemoveURL() { + ClassLoader classLoader = getDefaultClassLoader(); + URL[] urls = this.handle.getURLs(classLoader); URLClassLoader urlClassLoader = newURLClassLoader(urls); for (URL url : urls) { - assertTrue(handle.removeURL(urlClassLoader, url)); + assertTrue(this.handle.removeURL(urlClassLoader, url)); } } } diff --git a/microsphere-java-core/src/test/java/io/microsphere/collection/AbstractDequeTest.java b/microsphere-java-core/src/test/java/io/microsphere/collection/AbstractDequeTest.java index eb6aa11fe..df8696b1b 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/collection/AbstractDequeTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/collection/AbstractDequeTest.java @@ -3,9 +3,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import java.util.Iterator; import java.util.NoSuchElementException; -import java.util.Objects; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; @@ -28,107 +26,7 @@ class AbstractDequeTest { @BeforeEach void setUp() { - - deque = new AbstractDeque() { - - private String value; - - @Override - public Iterator iterator() { - return new Iterator() { - - private int cursor = 0; - - @Override - public boolean hasNext() { - return cursor == 0; - } - - @Override - public String next() { - if (cursor++ == 0) { - return value; - } else { - throw new NoSuchElementException(); - } - } - - @Override - public void remove() { - if (cursor <= 1) { - value = null; - } else { - throw new NoSuchElementException(); - } - } - }; - } - - @Override - public Iterator descendingIterator() { - return iterator(); - } - - @Override - public boolean offerFirst(String s) { - if (value == null) { - value = s; - return true; - } - return false; - } - - @Override - public boolean offerLast(String s) { - return offerFirst(s); - } - - @Override - public String pollFirst() { - String s = value; - value = null; - return s; - } - - @Override - public String pollLast() { - return pollFirst(); - } - - @Override - public String getFirst() { - return value; - } - - @Override - public String getLast() { - return getFirst(); - } - - @Override - public String peekFirst() { - return value; - } - - @Override - public String peekLast() { - return value; - } - - @Override - public boolean removeLastOccurrence(Object o) { - if (Objects.equals(o, value)) { - value = null; - return true; - } - return false; - } - - @Override - public int size() { - return 1; - } - }; + deque = new TestDeque<>(1); } @Test @@ -189,7 +87,7 @@ void testPeekLast() { @Test void testRemoveFirstOccurrence() { - assertTrue(deque.removeFirstOccurrence(null)); + assertFalse(deque.removeFirstOccurrence(null)); deque.add(TEST_VALUE); assertFalse(deque.removeFirstOccurrence("")); assertTrue(deque.removeFirstOccurrence(TEST_VALUE)); diff --git a/microsphere-java-core/src/test/java/io/microsphere/collection/DelegatingIteratorTest.java b/microsphere-java-core/src/test/java/io/microsphere/collection/DelegatingIteratorTest.java new file mode 100644 index 000000000..f29382d37 --- /dev/null +++ b/microsphere-java-core/src/test/java/io/microsphere/collection/DelegatingIteratorTest.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.microsphere.collection; + + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +import static io.microsphere.collection.ListUtils.ofArrayList; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link DelegatingIterator} Test + * + * @author Mercy + * @see DelegatingIterator + * @since 1.0.0 + */ +class DelegatingIteratorTest { + + private Iterator iterator; + + private DelegatingIterator delegatingIterator; + + @BeforeEach + void setUp() { + List list = ofArrayList("1", "2", "3"); + this.iterator = list.iterator(); + this.delegatingIterator = new DelegatingIterator<>(this.iterator); + } + + @Test + void testHasNext() { + assertTrue(delegatingIterator.hasNext()); + } + + @Test + void testNext() { + assertEquals("1", this.delegatingIterator.next()); + assertEquals("2", this.delegatingIterator.next()); + assertEquals("3", this.delegatingIterator.next()); + assertThrows(NoSuchElementException.class, this.delegatingIterator::next); + } + + @Test + void testRemove() { + while (this.delegatingIterator.hasNext()) { + this.delegatingIterator.next(); + this.delegatingIterator.remove(); + } + } + + @Test + void testForEachRemaining() { + this.delegatingIterator.forEachRemaining(Assertions::assertNotNull); + } + + @Test + void testGetDelegate() { + assertSame(this.delegatingIterator.getDelegate(), this.iterator); + } + + @Test + void testHashCode() { + assertEquals(this.delegatingIterator.hashCode(), this.iterator.hashCode()); + } + + @Test + void testEquals() { + assertEquals(this.delegatingIterator, this.iterator); + } + + @Test + void testToString() { + assertEquals(this.delegatingIterator.toString(), this.iterator.toString()); + } +} \ No newline at end of file diff --git a/microsphere-java-core/src/test/java/io/microsphere/collection/TestDeque.java b/microsphere-java-core/src/test/java/io/microsphere/collection/TestDeque.java new file mode 100644 index 000000000..f14674a7b --- /dev/null +++ b/microsphere-java-core/src/test/java/io/microsphere/collection/TestDeque.java @@ -0,0 +1,194 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.microsphere.collection; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Spliterator; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.stream.Stream; + +import static java.lang.Integer.MAX_VALUE; + +/** + * {@link AbstractDeque} class for testing + * + * @author Mercy + * @see AbstractDeque + * @since 1.0.0 + */ +public class TestDeque extends AbstractDeque { + + private final int maxCapacity; + + private final LinkedList delegate = new LinkedList<>(); + + public TestDeque() { + this(MAX_VALUE); + } + + public TestDeque(int maxCapacity) { + this.maxCapacity = maxCapacity; + } + + @Override + public void addFirst(E e) { + super.addFirst(e); + } + + @Override + public void addLast(E e) { + super.addLast(e); + } + + @Override + public E removeFirst() { + return super.removeFirst(); + } + + @Override + public E removeLast() { + return super.removeLast(); + } + + @Override + public boolean removeFirstOccurrence(Object o) { + return super.removeFirstOccurrence(o); + } + + @Override + public void push(E e) { + super.push(e); + } + + @Override + public E pop() { + return super.pop(); + } + + @Override + public boolean offer(E e) { + return super.offer(e); + } + + @Override + public E poll() { + return super.poll(); + } + + @Override + public E peek() { + return super.peek(); + } + + @Override + public Iterator iterator() { + return delegate.iterator(); + } + + @Override + public void forEach(Consumer action) { + delegate.forEach(action); + } + + @Override + public boolean removeIf(Predicate filter) { + return delegate.removeIf(filter); + } + + @Override + public Spliterator spliterator() { + return delegate.spliterator(); + } + + @Override + public Stream stream() { + return delegate.stream(); + } + + @Override + public Stream parallelStream() { + return delegate.parallelStream(); + } + + @Override + public Iterator descendingIterator() { + return delegate.descendingIterator(); + } + + @Override + public boolean offerFirst(E e) { + if (isFull()) { + return false; + } + return delegate.offerFirst(e); + } + + @Override + public boolean offerLast(E e) { + if (isFull()) { + return false; + } + return delegate.offerLast(e); + } + + @Override + public E pollFirst() { + return delegate.pollFirst(); + } + + @Override + public E pollLast() { + return delegate.pollLast(); + } + + @Override + public E getFirst() { + return delegate.getFirst(); + } + + @Override + public E getLast() { + return delegate.getLast(); + } + + @Override + public E peekFirst() { + return delegate.peekFirst(); + } + + @Override + public E peekLast() { + return delegate.peekLast(); + } + + @Override + public boolean removeLastOccurrence(Object o) { + return delegate.removeLastOccurrence(o); + } + + @Override + public int size() { + return delegate.size(); + } + + public boolean isFull() { + return this.size() >= this.maxCapacity; + } +} \ No newline at end of file diff --git a/microsphere-java-core/src/test/java/io/microsphere/concurrent/ExecutorUtilsTest.java b/microsphere-java-core/src/test/java/io/microsphere/concurrent/ExecutorUtilsTest.java index ec6866136..26d821203 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/concurrent/ExecutorUtilsTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/concurrent/ExecutorUtilsTest.java @@ -1,17 +1,24 @@ package io.microsphere.concurrent; import io.microsphere.AbstractTestCase; +import io.microsphere.util.ShutdownHookUtils; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import java.util.Iterator; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; +import java.util.concurrent.PriorityBlockingQueue; import static io.microsphere.concurrent.CustomizedThreadFactory.newThreadFactory; import static io.microsphere.concurrent.ExecutorUtils.shutdown; import static io.microsphere.concurrent.ExecutorUtils.shutdownOnExit; +import static io.microsphere.reflect.FieldUtils.getStaticFieldValue; import static java.util.concurrent.Executors.newSingleThreadExecutor; +import static java.util.concurrent.TimeUnit.MILLISECONDS; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; /** @@ -27,19 +34,41 @@ class ExecutorUtilsTest extends AbstractTestCase { @BeforeEach void setUp() { - executorService = newSingleThreadExecutor(newThreadFactory("ExecutorUtilsTest-", true)); - executorService.execute(() -> log("Running...")); + this.executorService = newSingleThreadExecutor(newThreadFactory("ExecutorUtilsTest-", true)); + this.executorService.execute(() -> log("Running...")); + } + + @AfterEach + void tearDown() { + this.executorService.shutdown(); } @Test - void testShutdownOnExit() { - shutdownOnExit(executorService, executorService, executorService); + void testShutdownOnExit() throws InterruptedException { + shutdownOnExit(this.executorService, this.executorService, this.executorService); + PriorityBlockingQueue shutdownHookCallbacks = getStaticFieldValue(ShutdownHookUtils.class, "shutdownHookCallbacks"); + assertNotNull(shutdownHookCallbacks); + + Iterator iterator = shutdownHookCallbacks.iterator(); + String classNamePrefix = ExecutorUtils.class.getName() + "$$Lambda/"; + while (iterator.hasNext()) { + Runnable callback = iterator.next(); + Class callbackClass = callback.getClass(); + String callbackClassName = callbackClass.getName(); + if (callbackClassName.startsWith(classNamePrefix)) { + callback.run(); + iterator.remove(); + } + } + if (this.executorService.awaitTermination(50, MILLISECONDS)) { + assertTrue(this.executorService.isShutdown()); + } } @Test void testShutdownForExecutor() { - assertTrue(shutdown((Executor) executorService)); - assertTrue(shutdown((Executor) executorService)); + assertTrue(shutdown((Executor) this.executorService)); + assertTrue(shutdown((Executor) this.executorService)); } @Test @@ -49,8 +78,8 @@ void testShutdownForExecutorOnNull() { @Test void testShutdownForExecutorService() { - assertTrue(shutdown(executorService)); - assertTrue(shutdown(executorService)); + assertTrue(shutdown(this.executorService)); + assertTrue(shutdown(this.executorService)); } @Test diff --git a/microsphere-java-core/src/test/java/io/microsphere/convert/AbstractConverterTest.java b/microsphere-java-core/src/test/java/io/microsphere/convert/AbstractConverterTest.java index b8a2273d3..26bf13fa1 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/convert/AbstractConverterTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/convert/AbstractConverterTest.java @@ -23,6 +23,7 @@ import static io.microsphere.lang.Prioritized.NORMAL_PRIORITY; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; /** * {@link AbstractConverter} Test @@ -31,31 +32,37 @@ * @see AbstractConverter * @since 1.0.0 */ -class AbstractConverterTest extends BaseConverterTest { +class AbstractConverterTest extends BaseConverterTest { @Override - protected AbstractConverter createConverter() { - return new AbstractConverter() { + protected AbstractConverter createConverter() { + return new AbstractConverter() { @Override - protected Object doConvert(Object source) throws Throwable { + protected String doConvert(String source) throws Throwable { return source; } @Override protected Integer resolvePriority() { + super.resolvePriority(); return null; } + + @Override + public int getPriority() { + return super.getPriority(); + } }; } @Override - protected Object getSource() throws Throwable { + protected String getSource() throws Throwable { return "test"; } @Override - protected Object getTarget() throws Throwable { + protected String getTarget() throws Throwable { return "test"; } @@ -65,8 +72,19 @@ void testGetPriority() { } @Test - void testConvertIfPossible() throws Throwable { + void testConvertIfPossible() { + } + @Test + void testConvertOnFailed() { + AbstractConverter converter = new AbstractConverter() { + @Override + protected String doConvert(String source) throws Throwable { + throw new Throwable("For testing"); + } + }; + + assertThrows(RuntimeException.class, () -> converter.convert(getSource())); } @Test @@ -76,4 +94,10 @@ void testGetConverter() { assertNotEquals(this.converter, new Object()); } + @Test + void testEquals() { + assertEquals(this.converter, this.converter); + assertNotEquals(this.converter, StringToBooleanConverter.INSTANCE); + assertNotEquals(this.converter, ObjectToStringConverter.INSTANCE); + } } diff --git a/microsphere-java-core/src/test/java/io/microsphere/event/EventListenerTest.java b/microsphere-java-core/src/test/java/io/microsphere/event/EventListenerTest.java index 77ed943f7..a916c5528 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/event/EventListenerTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/event/EventListenerTest.java @@ -19,7 +19,9 @@ import org.junit.jupiter.api.Test; import static io.microsphere.event.EventListener.findEventType; +import static io.microsphere.lang.Prioritized.NORMAL_PRIORITY; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; /** @@ -39,7 +41,24 @@ void testFindEventHierarchicalTypes() { } @Test - void testOnEvent() { + void testFindEventTypeOnNull() { + assertNull(findEventType((Class) null)); + } + + @Test + void testGetPriority() { + EventListener listener = new EventListener() { + @Override + public void onEvent(Event event) { + } + + @Override + public int getPriority() { + return EventListener.super.getPriority(); + } + }; + + assertEquals(NORMAL_PRIORITY, listener.getPriority()); } } \ No newline at end of file diff --git a/microsphere-java-core/src/test/java/io/microsphere/filter/FilterTest.java b/microsphere-java-core/src/test/java/io/microsphere/filter/FilterTest.java new file mode 100644 index 000000000..eae613363 --- /dev/null +++ b/microsphere-java-core/src/test/java/io/microsphere/filter/FilterTest.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.microsphere.filter; + + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link Filter} Test + * + * @author Mercy + * @see Filter + * @since 1.0.0 + */ +class FilterTest { + + private Filter filter; + + @BeforeEach + void setUp() { + this.filter = value -> "true".equalsIgnoreCase(value); + } + + @Test + void testAccept() { + assertFalse(this.filter.accept("test")); + assertTrue(this.filter.accept("true")); + } + + @Test + void testTest() { + assertFalse(this.filter.test("test")); + assertTrue(this.filter.test("true")); + } +} \ No newline at end of file diff --git a/microsphere-java-core/src/test/java/io/microsphere/filter/PackageNameClassFilterTest.java b/microsphere-java-core/src/test/java/io/microsphere/filter/PackageNameClassFilterTest.java index 8b02a5a86..dbd81c0b1 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/filter/PackageNameClassFilterTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/filter/PackageNameClassFilterTest.java @@ -20,5 +20,11 @@ void testAccept() { assertTrue(filter.accept(PackageNameClassFilterTest.class)); assertFalse(filter.accept(String.class)); assertFalse(filter.accept(null)); + + filter = new PackageNameClassFilter("io.microsphere", false); + assertFalse(filter.accept(PackageNameClassFilterTest.class)); + + filter = new PackageNameClassFilter("io.microsphere.filter", false); + assertTrue(filter.accept(PackageNameClassFilterTest.class)); } } \ No newline at end of file diff --git a/microsphere-java-core/src/test/java/io/microsphere/io/FastByteArrayInputStreamTest.java b/microsphere-java-core/src/test/java/io/microsphere/io/FastByteArrayInputStreamTest.java index 9d598ffce..6e10eae5b 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/io/FastByteArrayInputStreamTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/io/FastByteArrayInputStreamTest.java @@ -9,6 +9,7 @@ import static java.lang.Integer.MAX_VALUE; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; /** @@ -58,7 +59,7 @@ void testRead() { } @Test - void testRead1() { + void testReadWithRange() { byte[] bytes = new byte[8]; int offset = 0; int length = inputStream.available(); @@ -66,8 +67,12 @@ void testRead1() { assertEquals(TEST_VALUE, new String(bytes, offset, length)); length = TEST_VALUE.length() - TEST_OFFSET; - assertEquals(length, inputStream2.read(bytes, offset, length)); + assertEquals(length, inputStream2.read(bytes, offset, length * 2)); assertEquals("llo", new String(bytes, offset, length)); + + assertEquals(0, inputStream2.read(bytes, offset, 0)); + + assertEquals(-1, inputStream2.read(bytes, offset, length)); } @Test @@ -92,8 +97,10 @@ void testRead1OnIndexOutOfBounds() { @Test void testSkip() { + assertEquals(0, inputStream.skip(-1)); assertEquals(0, inputStream.skip(0)); assertEquals(1, inputStream.skip(1)); + assertEquals(4, inputStream.skip(MAX_VALUE)); } @Test @@ -120,7 +127,10 @@ void testReset() { @Test void testEquals() { + assertFalse(inputStream.equals(null)); + assertFalse(inputStream.equals("test")); assertEquals(inputStream, inputStream2); + assertEquals(inputStream, inputStream); } @Test diff --git a/microsphere-java-core/src/test/java/io/microsphere/io/FileUtilsTest.java b/microsphere-java-core/src/test/java/io/microsphere/io/FileUtilsTest.java index 80207a407..5980784f5 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/io/FileUtilsTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/io/FileUtilsTest.java @@ -1,7 +1,7 @@ package io.microsphere.io; import io.microsphere.AbstractTestCase; -import io.microsphere.process.ProcessExecutor; +import io.microsphere.lang.function.ThrowableConsumer; import org.junit.jupiter.api.Test; import java.io.File; @@ -16,6 +16,7 @@ import static io.microsphere.concurrent.CustomizedThreadFactory.newThreadFactory; import static io.microsphere.concurrent.ExecutorUtils.shutdown; import static io.microsphere.constants.FileConstants.CLASS; +import static io.microsphere.io.FileUtils.EMPTY_FILE_ARRAY; import static io.microsphere.io.FileUtils.cleanDirectory; import static io.microsphere.io.FileUtils.deleteDirectory; import static io.microsphere.io.FileUtils.deleteDirectoryOnExit; @@ -24,11 +25,13 @@ import static io.microsphere.io.FileUtils.getCanonicalFile; import static io.microsphere.io.FileUtils.getFileExtension; import static io.microsphere.io.FileUtils.isSymlink; +import static io.microsphere.io.FileUtils.listFiles; import static io.microsphere.io.FileUtils.resolveRelativePath; +import static io.microsphere.util.ArrayUtils.isNotEmpty; import static io.microsphere.util.ClassLoaderUtils.getClassResource; import static io.microsphere.util.ClassLoaderUtils.getResource; +import static io.microsphere.util.ExceptionUtils.wrap; import static io.microsphere.util.StringUtils.EMPTY_STRING; -import static io.microsphere.util.SystemUtils.IS_OS_WINDOWS; import static io.microsphere.util.SystemUtils.JAVA_IO_TMPDIR; import static java.lang.Thread.sleep; import static java.util.concurrent.Executors.newFixedThreadPool; @@ -114,63 +117,14 @@ void testDeleteDirectoryOnNotExists() throws IOException { @Test void testDeleteDirectoryOnIOException() throws Exception { - ExecutorService executor = newSingleThreadExecutor(); - executor.submit(this::testDeleteDirectoryOnIOException0); - shutdown(executor); - executor.awaitTermination(5, SECONDS); + handleDirectoryOnIOException(FileUtils::deleteDirectory); } - File testDeleteDirectoryOnIOException0() throws Exception { + @Test + void testDeleteDirectoryOnLink() throws Exception { File testDir = createRandomTempDirectory(); - - ExecutorService fileCreationExecutor = newSingleThreadExecutor(); - - AtomicBoolean creatingFile = new AtomicBoolean(true); - - long waitTime = 50L; - - fileCreationExecutor.submit(() -> { - while (creatingFile.get()) { - createRandomFile(testDir); - } - return null; - }); - - AtomicReference ioExceptionReference = new AtomicReference<>(); - - AtomicBoolean deletingDirectory = new AtomicBoolean(true); - - ExecutorService directoryDeletionExecutor = newSingleThreadExecutor(); - - directoryDeletionExecutor.submit(() -> { - while (deletingDirectory.get()) { - try { - deleteDirectory(testDir); - sleep(waitTime / 10); - } catch (IOException e) { - ioExceptionReference.set(e); - creatingFile.set(false); - deletingDirectory.set(false); - break; - } - } - return null; - }); - - for (int i = 0; i < 100; i++) { - if (creatingFile.get()) { - sleep(waitTime); - } - } - - shutdown(fileCreationExecutor); - shutdown(directoryDeletionExecutor); - - assertNotNull(ioExceptionReference.get()); - assertFalse(creatingFile.get()); - assertFalse(deletingDirectory.get()); - - return testDir; + File linkDir = makeLinkFile(testDir); + assertEquals(1, deleteDirectory(linkDir)); } @Test @@ -211,6 +165,32 @@ void testForceDeleteOnSingleFile() throws IOException { assertFalse(tempFile.exists()); } + @Test + void testListFiles() throws IOException { + File testDir = createRandomTempDirectory(); + assertEquals(EMPTY_FILE_ARRAY, listFiles(testDir)); + + createRandomFile(testDir); + assertTrue(isNotEmpty(listFiles(testDir))); + + deleteDirectoryOnExit(testDir); + } + + @Test + void testListFilesOnNull() { + assertEquals(EMPTY_FILE_ARRAY, listFiles(null)); + } + + @Test + void testListFilesOnNotFound() { + assertEquals(EMPTY_FILE_ARRAY, listFiles(new File("not-found"))); + } + + @Test + void testListFilesOnFile() throws IOException { + assertEquals(EMPTY_FILE_ARRAY, listFiles(createRandomTempFile())); + } + @Test void testForceDelete() throws IOException { File testDir = createRandomTempDirectory(); @@ -237,13 +217,16 @@ void testForceDeleteOnIOException() throws Exception { // status : 0 -> init // status : 1 -> writing // status : 2 -> deleting - AtomicInteger status = new AtomicInteger(0); + int init = 0; + int writing = 1; + int deleting = 2; + AtomicInteger status = new AtomicInteger(init); executor.submit(() -> { synchronized (testFile) { try (FileOutputStream outputStream = new FileOutputStream(testFile, true)) { outputStream.write('a'); - status.set(1); + status.set(writing); // wait for notification testFile.wait(); } @@ -252,15 +235,15 @@ void testForceDeleteOnIOException() throws Exception { }); executor.submit(() -> { - while (status.get() != 1) { + while (status.get() != writing) { } assertThrows(IOException.class, () -> forceDelete(testFile)); - status.set(2); + status.set(deleting); return null; }); executor.submit(() -> { - while (status.get() != 2) { + while (status.get() != deleting) { } synchronized (testFile) { testFile.notify(); @@ -280,8 +263,12 @@ void testForceDeleteOnExit() throws IOException { } @Test - void testDeleteDirectoryOnExit() throws IOException { + void testDeleteDirectoryOnExit() throws Exception { File tempDir = createRandomTempDirectory(); + + File link = makeLinkFile(tempDir); + deleteDirectoryOnExit(link); + for (int i = 0; i < 10; i++) { if (i % 2 == 0) { createRandomDirectory(tempDir); @@ -298,17 +285,11 @@ void testDeleteDirectoryOnExitOnNotExists() throws IOException { } @Test - void testIsSymlink() throws IOException { - if (IS_OS_WINDOWS) { - assertFalse(isSymlink(new File(""))); - } else { - File tempDir = createRandomTempDirectory(); - File targetFile = createRandomFile(tempDir); - File linkFile = new File(tempDir, "link"); - ProcessExecutor processExecutor = new ProcessExecutor("ln", "-s", targetFile.getAbsolutePath(), linkFile.getAbsolutePath()); - processExecutor.execute(System.out); - assertTrue(isSymlink(linkFile)); - } + void testIsSymlink() throws Exception { + File tempDir = createRandomTempDirectory(); + File targetFile = createRandomFile(tempDir); + File linkFile = makeLinkFile(targetFile); + assertTrue(isSymlink(linkFile)); } @Test @@ -322,4 +303,67 @@ void testGetCanonicalFile() { assertEquals(getCanonicalFile(tempFile), getCanonicalFile(getCanonicalFile(tempFile))); } + void handleDirectoryOnIOException(ThrowableConsumer directoryHandler) throws Exception { + ExecutorService executor = newSingleThreadExecutor(); + executor.submit(() -> handleDirectoryOnIOException0(directoryHandler)); + shutdown(executor); + executor.awaitTermination(1, SECONDS); + } + + File handleDirectoryOnIOException0(ThrowableConsumer directoryHandler) throws Exception { + File testDir = createRandomTempDirectory(); + + ExecutorService fileCreationExecutor = newSingleThreadExecutor(); + + AtomicBoolean creatingFile = new AtomicBoolean(true); + + long waitTime = 50L; + + fileCreationExecutor.submit(() -> { + while (creatingFile.get()) { + createRandomFile(testDir); + } + return null; + }); + + AtomicReference ioExceptionReference = new AtomicReference<>(); + + AtomicBoolean deletingDirectory = new AtomicBoolean(true); + + ExecutorService directoryDeletionExecutor = newSingleThreadExecutor(); + + directoryDeletionExecutor.submit(() -> { + while (deletingDirectory.get()) { + try { + directoryHandler.accept(testDir); + sleep(waitTime / 10); + } catch (IOException e) { + ioExceptionReference.set(e); + creatingFile.set(false); + deletingDirectory.set(false); + logger.trace(e.getMessage(), e); + break; + } catch (Throwable e) { + throw wrap(e, Exception.class); + } + } + return null; + }); + + for (int i = 0; i < 100; i++) { + if (creatingFile.get()) { + sleep(waitTime); + } + } + + shutdown(fileCreationExecutor); + shutdown(directoryDeletionExecutor); + + assertNotNull(ioExceptionReference.get()); + assertFalse(creatingFile.get()); + assertFalse(deletingDirectory.get()); + + return testDir; + } + } \ No newline at end of file diff --git a/microsphere-java-core/src/test/java/io/microsphere/io/StandardFileWatchServiceTest.java b/microsphere-java-core/src/test/java/io/microsphere/io/StandardFileWatchServiceTest.java index 7f5ca3601..6d6c0763d 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/io/StandardFileWatchServiceTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/io/StandardFileWatchServiceTest.java @@ -19,6 +19,7 @@ import io.microsphere.AbstractTestCase; import io.microsphere.io.event.DefaultFileChangedListener; import io.microsphere.io.event.FileChangedEvent; +import io.microsphere.io.event.FileChangedEvent.Kind; import io.microsphere.io.event.FileChangedListener; import io.microsphere.io.event.LoggingFileChangedListener; import io.microsphere.lang.function.ThrowableAction; @@ -37,19 +38,32 @@ import static io.microsphere.concurrent.ExecutorUtils.shutdown; import static io.microsphere.io.FileUtils.deleteDirectory; import static io.microsphere.io.FileUtils.forceDelete; +import static io.microsphere.io.StandardFileWatchService.ALL_WATCH_EVENT_KINDS; +import static io.microsphere.io.StandardFileWatchService.toKind; +import static io.microsphere.io.StandardFileWatchService.toWatchEventKinds; import static io.microsphere.io.event.FileChangedEvent.Kind.CREATED; import static io.microsphere.io.event.FileChangedEvent.Kind.DELETED; +import static io.microsphere.io.event.FileChangedEvent.Kind.MODIFIED; import static io.microsphere.io.event.FileChangedEvent.Kind.values; +import static io.microsphere.util.ArrayUtils.ofArray; import static io.microsphere.util.ClassLoaderUtils.getResource; import static io.microsphere.util.ExceptionUtils.wrap; import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.file.Files.copy; import static java.nio.file.Files.write; import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; +import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; +import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE; +import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; +import static java.nio.file.StandardWatchEventKinds.OVERFLOW; import static java.util.concurrent.Executors.newSingleThreadExecutor; import static java.util.concurrent.ForkJoinPool.commonPool; import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * {@link StandardFileWatchService} Test For File @@ -75,6 +89,34 @@ void tearDown() throws Exception { deleteDirectory(this.testDir); } + @Test + void testToWatchEventKinds() { + assertArrayEquals(ALL_WATCH_EVENT_KINDS, toWatchEventKinds()); + assertArrayEquals(ALL_WATCH_EVENT_KINDS, toWatchEventKinds(new Kind[0])); + assertArrayEquals(ALL_WATCH_EVENT_KINDS, toWatchEventKinds((Kind[]) null)); + assertArrayEquals(ALL_WATCH_EVENT_KINDS, toWatchEventKinds(CREATED, DELETED, MODIFIED)); + assertArrayEquals(ofArray(ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE), toWatchEventKinds(CREATED, MODIFIED, DELETED)); + } + + @Test + void testToWatchEventKind() { + assertArrayEquals(ALL_WATCH_EVENT_KINDS, toWatchEventKinds()); + assertArrayEquals(ALL_WATCH_EVENT_KINDS, toWatchEventKinds(new Kind[0])); + assertArrayEquals(ALL_WATCH_EVENT_KINDS, toWatchEventKinds((Kind[]) null)); + } + + @Test + void testToKind() { + assertEquals(CREATED, toKind(ENTRY_CREATE)); + assertEquals(MODIFIED, toKind(ENTRY_MODIFY)); + assertEquals(DELETED, toKind(ENTRY_DELETE)); + } + + @Test + void testToKindOnOverflow() { + assertThrows(IllegalArgumentException.class, () -> toKind(OVERFLOW)); + } + @Test void testFile() throws Exception { URL resource = getResource(super.classLoader, "test.txt"); @@ -93,9 +135,14 @@ void testFile() throws Exception { // start StandardFileWatchService fileWatchService.start(); + + assertTrue(fileWatchService.isStarted()); + // start again assertThrows(IllegalStateException.class, fileWatchService::start); + assertTrue(fileWatchService.isStarted()); + // copy file Path sourcePath = sourceFile.toPath(); Path targetFilePath = targetFile.toPath(); @@ -103,6 +150,10 @@ void testFile() throws Exception { // await for completion countDownLatch.await(); + + fileWatchService.stop(); + + assertFalse(fileWatchService.isStarted()); } } @@ -131,8 +182,12 @@ public void onFileDeleted(FileChangedEvent event) { fileWatchService.start(); + assertTrue(fileWatchService.isStarted()); + assertThrows(IllegalStateException.class, fileWatchService::start); + assertTrue(fileWatchService.isStarted()); + // create a test file File testFile = createRandomFile(testDir); @@ -146,6 +201,10 @@ public void onFileDeleted(FileChangedEvent event) { while (fileReference.get() == null) { // spin } + + fileWatchService.stop(); + + assertFalse(fileWatchService.isStarted()); } } diff --git a/microsphere-java-core/src/test/java/io/microsphere/io/filter/NameFileFilterTest.java b/microsphere-java-core/src/test/java/io/microsphere/io/filter/NameFileFilterTest.java new file mode 100644 index 000000000..b30f7c637 --- /dev/null +++ b/microsphere-java-core/src/test/java/io/microsphere/io/filter/NameFileFilterTest.java @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.microsphere.io.filter; + + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.File; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link NameFileFilter} Test + * + * @author Mercy + * @see NameFileFilter + * @since 1.0.0 + */ +class NameFileFilterTest { + + private static final String FILE_NAME = "Test.txt"; + + private File file; + + @BeforeEach + void setUp() { + this.file = new File(FILE_NAME); + } + + @Test + void testAccept() { + NameFileFilter filter = new NameFileFilter(FILE_NAME); + assertTrue(filter.accept(this.file)); + + filter = new NameFileFilter(FILE_NAME.toUpperCase()); + assertFalse(filter.accept(this.file)); + + filter = new NameFileFilter(FILE_NAME.toLowerCase()); + assertFalse(filter.accept(this.file)); + } + + @Test + void testAcceptOnIgnoreCaseSensitive() { + NameFileFilter filter = new NameFileFilter(FILE_NAME, false); + assertTrue(filter.accept(this.file)); + + filter = new NameFileFilter(FILE_NAME.toUpperCase(), false); + assertTrue(filter.accept(this.file)); + + filter = new NameFileFilter(FILE_NAME.toLowerCase(), false); + assertTrue(filter.accept(this.file)); + } +} \ No newline at end of file diff --git a/microsphere-java-core/src/test/java/io/microsphere/json/JSONUtilsTest.java b/microsphere-java-core/src/test/java/io/microsphere/json/JSONUtilsTest.java index 76420059c..d50fa6507 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/json/JSONUtilsTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/json/JSONUtilsTest.java @@ -46,6 +46,7 @@ import static io.microsphere.collection.Sets.ofSet; import static io.microsphere.json.JSONObject.NULL; import static io.microsphere.json.JSONUtils.append; +import static io.microsphere.json.JSONUtils.appendName; import static io.microsphere.json.JSONUtils.convertValue; import static io.microsphere.json.JSONUtils.determineElementClass; import static io.microsphere.json.JSONUtils.escape; @@ -99,219 +100,219 @@ void setUp() { @Test void testAppendOnBoolean() { - append(jsonBuilder, "name", true); - assertEquals("\"name\":true", jsonBuilder.toString()); + append(this.jsonBuilder, "name", true); + assertEquals("\"name\":true", this.jsonBuilder.toString()); } @Test void testAppendOnByte() { - append(jsonBuilder, "name", (byte) 1); - assertEquals("\"name\":1", jsonBuilder.toString()); + append(this.jsonBuilder, "name", (byte) 1); + assertEquals("\"name\":1", this.jsonBuilder.toString()); } @Test void testAppendOnShort() { - append(jsonBuilder, "name", (short) 1); - assertEquals("\"name\":1", jsonBuilder.toString()); + append(this.jsonBuilder, "name", (short) 1); + assertEquals("\"name\":1", this.jsonBuilder.toString()); } @Test void testAppendOnInt() { - append(jsonBuilder, "name", 1); - assertEquals("\"name\":1", jsonBuilder.toString()); + append(this.jsonBuilder, "name", 1); + assertEquals("\"name\":1", this.jsonBuilder.toString()); } @Test void testAppendOnLong() { - append(jsonBuilder, "name", 1L); - assertEquals("\"name\":1", jsonBuilder.toString()); + append(this.jsonBuilder, "name", 1L); + assertEquals("\"name\":1", this.jsonBuilder.toString()); } @Test void testAppendOnFloat() { - append(jsonBuilder, "name", 1.0f); - assertEquals("\"name\":1.0", jsonBuilder.toString()); + append(this.jsonBuilder, "name", 1.0f); + assertEquals("\"name\":1.0", this.jsonBuilder.toString()); } @Test void testAppendOnDouble() { - append(jsonBuilder, "name", 1.0); - assertEquals("\"name\":1.0", jsonBuilder.toString()); + append(this.jsonBuilder, "name", 1.0); + assertEquals("\"name\":1.0", this.jsonBuilder.toString()); } @Test void testAppendOnChar() { - append(jsonBuilder, "name", 'a'); - assertEquals("\"name\":\"a\"", jsonBuilder.toString()); + append(this.jsonBuilder, "name", 'a'); + assertEquals("\"name\":\"a\"", this.jsonBuilder.toString()); } @Test void testAppendOnBooleanObject() { - append(jsonBuilder, "name", TRUE); - assertEquals("\"name\":true", jsonBuilder.toString()); + append(this.jsonBuilder, "name", TRUE); + assertEquals("\"name\":true", this.jsonBuilder.toString()); } @Test void testAppendOnByteObject() { - append(jsonBuilder, "name", valueOf((byte) 1)); - assertEquals("\"name\":1", jsonBuilder.toString()); + append(this.jsonBuilder, "name", valueOf((byte) 1)); + assertEquals("\"name\":1", this.jsonBuilder.toString()); } @Test void testAppendOnShortObject() { - append(jsonBuilder, "name", Short.valueOf((short) 1)); - assertEquals("\"name\":1", jsonBuilder.toString()); + append(this.jsonBuilder, "name", Short.valueOf((short) 1)); + assertEquals("\"name\":1", this.jsonBuilder.toString()); } @Test void testAppendOnIntegerObject() { - append(jsonBuilder, "name", Integer.valueOf(1)); - assertEquals("\"name\":1", jsonBuilder.toString()); + append(this.jsonBuilder, "name", Integer.valueOf(1)); + assertEquals("\"name\":1", this.jsonBuilder.toString()); } @Test void testAppendOnLongObject() { - append(jsonBuilder, "name", Long.valueOf(1L)); - assertEquals("\"name\":1", jsonBuilder.toString()); + append(this.jsonBuilder, "name", Long.valueOf(1L)); + assertEquals("\"name\":1", this.jsonBuilder.toString()); } @Test void testAppendOnFloatObject() { - append(jsonBuilder, "name", Float.valueOf(1.0f)); - assertEquals("\"name\":1.0", jsonBuilder.toString()); + append(this.jsonBuilder, "name", Float.valueOf(1.0f)); + assertEquals("\"name\":1.0", this.jsonBuilder.toString()); } @Test void testAppendOnDoubleObject() { - append(jsonBuilder, "name", Double.valueOf(1.0)); - assertEquals("\"name\":1.0", jsonBuilder.toString()); + append(this.jsonBuilder, "name", Double.valueOf(1.0)); + assertEquals("\"name\":1.0", this.jsonBuilder.toString()); } @Test void testAppendOnCharacterObject() { - append(jsonBuilder, "name", valueOf('a')); - assertEquals("\"name\":\"a\"", jsonBuilder.toString()); + append(this.jsonBuilder, "name", valueOf('a')); + assertEquals("\"name\":\"a\"", this.jsonBuilder.toString()); } @Test void testAppendOnString() { - append(jsonBuilder, "name", "a"); - assertEquals("\"name\":\"a\"", jsonBuilder.toString()); + append(this.jsonBuilder, "name", "a"); + assertEquals("\"name\":\"a\"", this.jsonBuilder.toString()); } @Test void testAppendOnType() { - append(jsonBuilder, "name", String.class); - assertEquals("\"name\":\"java.lang.String\"", jsonBuilder.toString()); + append(this.jsonBuilder, "name", String.class); + assertEquals("\"name\":\"java.lang.String\"", this.jsonBuilder.toString()); } @Test void testAppendOnBooleanObjectArray() { - append(jsonBuilder, "name", new Boolean[]{TRUE, FALSE}); - assertEquals("\"name\":[true,false]", jsonBuilder.toString()); + append(this.jsonBuilder, "name", new Boolean[]{TRUE, FALSE}); + assertEquals("\"name\":[true,false]", this.jsonBuilder.toString()); } @Test void testAppendOnByteObjectArray() { - append(jsonBuilder, "name", new Byte[]{(byte) 1, (byte) 2}); - assertEquals("\"name\":[1,2]", jsonBuilder.toString()); + append(this.jsonBuilder, "name", new Byte[]{(byte) 1, (byte) 2}); + assertEquals("\"name\":[1,2]", this.jsonBuilder.toString()); } @Test void testAppendOnShortObjectArray() { - append(jsonBuilder, "name", new Short[]{(short) 1, (short) 2}); - assertEquals("\"name\":[1,2]", jsonBuilder.toString()); + append(this.jsonBuilder, "name", new Short[]{(short) 1, (short) 2}); + assertEquals("\"name\":[1,2]", this.jsonBuilder.toString()); } @Test void testAppendOnIntegerObjectArray() { - append(jsonBuilder, "name", new Integer[]{1, 2}); - assertEquals("\"name\":[1,2]", jsonBuilder.toString()); + append(this.jsonBuilder, "name", new Integer[]{1, 2}); + assertEquals("\"name\":[1,2]", this.jsonBuilder.toString()); } @Test void testAppendOnLongObjectArray() { - append(jsonBuilder, "name", new Long[]{1L, 2L}); - assertEquals("\"name\":[1,2]", jsonBuilder.toString()); + append(this.jsonBuilder, "name", new Long[]{1L, 2L}); + assertEquals("\"name\":[1,2]", this.jsonBuilder.toString()); } @Test void testAppendOnFloatObjectArray() { - append(jsonBuilder, "name", new Float[]{1.0f, 2.0f}); - assertEquals("\"name\":[1.0,2.0]", jsonBuilder.toString()); + append(this.jsonBuilder, "name", new Float[]{1.0f, 2.0f}); + assertEquals("\"name\":[1.0,2.0]", this.jsonBuilder.toString()); } @Test void testAppendOnDoubleObjectArray() { - append(jsonBuilder, "name", new Double[]{1.0, 2.0}); - assertEquals("\"name\":[1.0,2.0]", jsonBuilder.toString()); + append(this.jsonBuilder, "name", new Double[]{1.0, 2.0}); + assertEquals("\"name\":[1.0,2.0]", this.jsonBuilder.toString()); } @Test void testAppendOnCharacterObjectArray() { - append(jsonBuilder, "name", new Character[]{'a', 'b'}); - assertEquals("\"name\":[\"a\",\"b\"]", jsonBuilder.toString()); + append(this.jsonBuilder, "name", new Character[]{'a', 'b'}); + assertEquals("\"name\":[\"a\",\"b\"]", this.jsonBuilder.toString()); } @Test void testAppendOnBooleanArray() { - append(jsonBuilder, "name", new boolean[]{true, false}); - assertEquals("\"name\":[true,false]", jsonBuilder.toString()); + append(this.jsonBuilder, "name", new boolean[]{true, false}); + assertEquals("\"name\":[true,false]", this.jsonBuilder.toString()); } @Test void testAppendOnByteArray() { - append(jsonBuilder, "name", new byte[]{1, 2}); - assertEquals("\"name\":[1,2]", jsonBuilder.toString()); + append(this.jsonBuilder, "name", new byte[]{1, 2}); + assertEquals("\"name\":[1,2]", this.jsonBuilder.toString()); } @Test void testAppendOnShortArray() { - append(jsonBuilder, "name", new short[]{1, 2}); - assertEquals("\"name\":[1,2]", jsonBuilder.toString()); + append(this.jsonBuilder, "name", new short[]{1, 2}); + assertEquals("\"name\":[1,2]", this.jsonBuilder.toString()); } @Test void testAppendOnIntegerArray() { - append(jsonBuilder, "name", new int[]{1, 2}); - assertEquals("\"name\":[1,2]", jsonBuilder.toString()); + append(this.jsonBuilder, "name", new int[]{1, 2}); + assertEquals("\"name\":[1,2]", this.jsonBuilder.toString()); } @Test void testAppendOnLongArray() { - append(jsonBuilder, "name", new long[]{1, 2}); - assertEquals("\"name\":[1,2]", jsonBuilder.toString()); + append(this.jsonBuilder, "name", new long[]{1, 2}); + assertEquals("\"name\":[1,2]", this.jsonBuilder.toString()); } @Test void testAppendOnFloatArray() { - append(jsonBuilder, "name", new float[]{1.0f, 2.0f}); - assertEquals("\"name\":[1.0,2.0]", jsonBuilder.toString()); + append(this.jsonBuilder, "name", new float[]{1.0f, 2.0f}); + assertEquals("\"name\":[1.0,2.0]", this.jsonBuilder.toString()); } @Test void testAppendOnDoubleArray() { - append(jsonBuilder, "name", new double[]{1.0, 2.0}); - assertEquals("\"name\":[1.0,2.0]", jsonBuilder.toString()); + append(this.jsonBuilder, "name", new double[]{1.0, 2.0}); + assertEquals("\"name\":[1.0,2.0]", this.jsonBuilder.toString()); } @Test void testAppendOnCharArray() { - append(jsonBuilder, "name", new char[]{'a', 'b'}); - assertEquals("\"name\":[\"a\",\"b\"]", jsonBuilder.toString()); + append(this.jsonBuilder, "name", new char[]{'a', 'b'}); + assertEquals("\"name\":[\"a\",\"b\"]", this.jsonBuilder.toString()); } @Test void testAppendOnStringArray() { - append(jsonBuilder, "name", new String[]{"a", "b"}); - assertEquals("\"name\":[\"a\",\"b\"]", jsonBuilder.toString()); + append(this.jsonBuilder, "name", new String[]{"a", "b"}); + assertEquals("\"name\":[\"a\",\"b\"]", this.jsonBuilder.toString()); } @Test void testAppendOnObjectAsArray() { Object value = new boolean[]{TRUE, FALSE}; - append(jsonBuilder, "name", value); - assertEquals("\"name\":[true,false]", jsonBuilder.toString()); + append(this.jsonBuilder, "name", value); + assertEquals("\"name\":[true,false]", this.jsonBuilder.toString()); } @Test @@ -328,44 +329,58 @@ void testAppendOnObjectAsMap() { "string", "8", "strings", new String[]{"9", "10"} ); - append(jsonBuilder, "name", value); + append(this.jsonBuilder, "name", value); } @Test void testAppendOnObjectAsIterable() { Object value = ofList(true, (byte) 1, '2', 3.0, 4.0f, 5L, 6, (short) 7, "8", ofArray("9", "10")); - append(jsonBuilder, "name", value); - assertEquals("\"name\":[true,1,\"2\",3.0,4.0,5,6,7,\"8\",[\"9\",\"10\"]]", jsonBuilder.toString()); + append(this.jsonBuilder, "name", value); + assertEquals("\"name\":[true,1,\"2\",3.0,4.0,5,6,7,\"8\",[\"9\",\"10\"]]", this.jsonBuilder.toString()); } @Test void testAppendOnObjectAsString() { Object value = "s"; - append(jsonBuilder, "name", value); - assertEquals("\"name\":\"s\"", jsonBuilder.toString()); + append(this.jsonBuilder, "name", value); + assertEquals("\"name\":\"s\"", this.jsonBuilder.toString()); } @Test void testAppendOnObjectAsInteger() { Object value = 1; - append(jsonBuilder, "name", value); - assertEquals("\"name\":1", jsonBuilder.toString()); + append(this.jsonBuilder, "name", value); + assertEquals("\"name\":1", this.jsonBuilder.toString()); } @Test void testAppendOnGenericArray() { TimeUnit[] values = ofArray(DAYS, HOURS, MINUTES); - append(jsonBuilder, "name", values); - assertEquals("\"name\":[\"DAYS\",\"HOURS\",\"MINUTES\"]", jsonBuilder.toString()); + append(this.jsonBuilder, "name", values); + assertEquals("\"name\":[\"DAYS\",\"HOURS\",\"MINUTES\"]", this.jsonBuilder.toString()); } @Test void testAppendOnTypeArray() { Class[] classes = ofArray(String.class, Integer.class); - append(jsonBuilder, "name", classes); - assertEquals("\"name\":[\"java.lang.String\",\"java.lang.Integer\"]", jsonBuilder.toString()); + append(this.jsonBuilder, "name", classes); + assertEquals("\"name\":[\"java.lang.String\",\"java.lang.Integer\"]", this.jsonBuilder.toString()); } + @Test + void testAppendName() { + appendName(this.jsonBuilder, null); + assertEquals(EMPTY_STRING, this.jsonBuilder.toString()); + + appendName(this.jsonBuilder, ""); + assertEquals(EMPTY_STRING, this.jsonBuilder.toString()); + + appendName(this.jsonBuilder, " "); + assertEquals(EMPTY_STRING, this.jsonBuilder.toString()); + + appendName(this.jsonBuilder, "name"); + assertEquals("\"name\":", this.jsonBuilder.toString()); + } @Test void testIsUnknownClass() { diff --git a/microsphere-java-core/src/test/java/io/microsphere/lang/ClassDataRepositoryTest.java b/microsphere-java-core/src/test/java/io/microsphere/lang/ClassDataRepositoryTest.java index 752b0eb86..be40025a9 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/lang/ClassDataRepositoryTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/lang/ClassDataRepositoryTest.java @@ -18,20 +18,18 @@ import io.microsphere.AbstractTestCase; import io.microsphere.reflect.ReflectionUtils; -import io.microsphere.util.VersionUtils; import org.junit.jupiter.api.Test; import javax.annotation.Nonnull; -import java.net.URL; import java.util.Map; import java.util.Set; +import static io.microsphere.lang.ClassDataRepository.INSTANCE; import static io.microsphere.util.ClassPathUtils.getClassPaths; -import static io.microsphere.util.VersionUtils.CURRENT_JAVA_VERSION; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * {@link ClassDataRepository} Test @@ -42,22 +40,28 @@ */ class ClassDataRepositoryTest extends AbstractTestCase { - private static final ClassDataRepository repository = ClassDataRepository.INSTANCE; + private final ClassDataRepository repository = INSTANCE; @Test void testGetClassNamesInClassPath() { Set classPaths = getClassPaths(); for (String classPath : classPaths) { - Set classNames = repository.getClassNamesInClassPath(classPath, true); + Set classNames = this.repository.getClassNamesInClassPath(classPath, true); assertNotNull(classNames); } } + @Test + void testGetClassNamesInClassPathOnNotFoundClassPath() { + Set classNames = this.repository.getClassNamesInClassPath("not-found", true); + assertTrue(classNames.isEmpty()); + } + @Test void testGetClassNamesInPackageWithName() { - Set packageNames = repository.getAllPackageNamesInClassPaths(); + Set packageNames = this.repository.getAllPackageNamesInClassPaths(); for (String packageName : packageNames) { - Set classNames = repository.getClassNamesInPackage(packageName); + Set classNames = this.repository.getClassNamesInPackage(packageName); assertFalse(classNames.isEmpty()); assertThrows(UnsupportedOperationException.class, classNames::clear); } @@ -66,31 +70,36 @@ void testGetClassNamesInPackageWithName() { @Test void testGetClassNamesInPackage() { Package pkg = ClassDataRepositoryTest.class.getPackage(); - Set classNames = repository.getClassNamesInPackage(pkg); + Set classNames = this.repository.getClassNamesInPackage(pkg); assertFalse(classNames.isEmpty()); assertThrows(UnsupportedOperationException.class, classNames::clear); } + @Test + void testGetClassNamesInPackageOnNotFoundPackage() { + Set classNames = this.repository.getClassNamesInPackage("not-found-package"); + assertTrue(classNames.isEmpty()); + } @Test void testGetAllPackageNamesInClassPaths() { - Set packageNames = repository.getAllPackageNamesInClassPaths(); + Set packageNames = this.repository.getAllPackageNamesInClassPaths(); assertFalse(packageNames.isEmpty()); assertThrows(UnsupportedOperationException.class, packageNames::clear); } @Test void testFindClassPath() { - String classPath = repository.findClassPath(ReflectionUtils.class); + String classPath = this.repository.findClassPath(ReflectionUtils.class); assertNotNull(classPath); - classPath = repository.findClassPath(Nonnull.class); + classPath = this.repository.findClassPath(Nonnull.class); assertNotNull(classPath); } @Test void testGetAllClassNamesMapInClassPath() { - Map> allClassNamesMapInClassPath = repository.getClassPathToClassNamesMap(); + Map> allClassNamesMapInClassPath = this.repository.getClassPathToClassNamesMap(); assertFalse(allClassNamesMapInClassPath.isEmpty()); assertThrows(UnsupportedOperationException.class, allClassNamesMapInClassPath::clear); @@ -98,28 +107,8 @@ void testGetAllClassNamesMapInClassPath() { @Test void testGetAllClassNamesInClassPath() { - Set allClassNames = repository.getAllClassNamesInClassPaths(); + Set allClassNames = this.repository.getAllClassNamesInClassPaths(); assertFalse(allClassNames.isEmpty()); assertThrows(UnsupportedOperationException.class, allClassNames::clear); - - } - - @Test - void testGetCodeSourceLocation() { - URL codeSourceLocation = null; - - codeSourceLocation = repository.getCodeSourceLocation(ClassDataRepositoryTest.class); - assertNotNull(codeSourceLocation); - - codeSourceLocation = repository.getCodeSourceLocation(Nonnull.class); - assertNotNull(codeSourceLocation); - - codeSourceLocation = repository.getCodeSourceLocation(String.class); - if (CURRENT_JAVA_VERSION.le(VersionUtils.JAVA_VERSION_8)) { - assertNotNull(codeSourceLocation); - } else { - assertNull(codeSourceLocation); - } } - -} +} \ No newline at end of file diff --git a/microsphere-java-core/src/test/java/io/microsphere/lang/DeprecationTest.java b/microsphere-java-core/src/test/java/io/microsphere/lang/DeprecationTest.java index 9aedf1083..41f398f8e 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/lang/DeprecationTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/lang/DeprecationTest.java @@ -16,12 +16,19 @@ */ package io.microsphere.lang; +import io.microsphere.lang.Deprecation.Level; import io.microsphere.util.Version; import org.junit.jupiter.api.Test; +import static io.microsphere.lang.Deprecation.Level.DEFAULT; +import static io.microsphere.lang.Deprecation.Level.REMOVAL; +import static io.microsphere.lang.Deprecation.of; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * {@link Deprecation} Test @@ -40,13 +47,16 @@ public class DeprecationTest { public static final String LINK = "https://github.com/microsphere-projects/microsphere-java"; - public static Deprecation.Level LEVEL = Deprecation.Level.REMOVAL; + public static Level LEVEL = REMOVAL; - public static Deprecation DEPRECATION = Deprecation.of(SINCE, REPLACEMENT, REASON, LINK, LEVEL); + public static Deprecation DEPRECATION = of(SINCE, REPLACEMENT, REASON, LINK, LEVEL); @Test void test() { - Deprecation deprecation = Deprecation.of(SINCE, REPLACEMENT, REASON, LINK, LEVEL); + Deprecation deprecation = of(SINCE, REPLACEMENT, REASON, LINK, LEVEL); + + assertTrue(deprecation.equals(deprecation)); + assertFalse(deprecation.equals(LEVEL)); assertObjectMethods(deprecation); assertEquals(Version.of(SINCE), deprecation.getSince()); @@ -57,61 +67,59 @@ void test() { assertNotNull(deprecation.toString()); assertEquals(deprecation, new Deprecation(deprecation)); assertEquals(deprecation.hashCode(), new Deprecation(deprecation).hashCode()); + assertNotEquals(of(SINCE, REPLACEMENT, REASON, LINK), deprecation); - deprecation = Deprecation.of(SINCE, REPLACEMENT, REASON, LINK); + deprecation = of(SINCE, REPLACEMENT, REASON, LINK); assertObjectMethods(deprecation); assertEquals(Version.of(SINCE), deprecation.getSince()); assertEquals(REPLACEMENT, deprecation.getReplacement()); assertEquals(REASON, deprecation.getReason()); assertEquals(LINK, deprecation.getLink()); - assertEquals(Deprecation.Level.DEFAULT, deprecation.getLevel()); + assertEquals(DEFAULT, deprecation.getLevel()); assertNotNull(deprecation.toString()); assertEquals(deprecation, new Deprecation(deprecation)); + assertEquals(deprecation, of(SINCE, REPLACEMENT, REASON, LINK, null)); assertEquals(deprecation.hashCode(), new Deprecation(deprecation).hashCode()); + assertNotEquals(of(SINCE, REPLACEMENT, REASON, LINK + ".git"), deprecation); - deprecation = Deprecation.of(SINCE, REPLACEMENT, REASON); - assertObjectMethods(deprecation); - assertEquals(Version.of(SINCE), deprecation.getSince()); - assertEquals(REPLACEMENT, deprecation.getReplacement()); - assertEquals(REASON, deprecation.getReason()); - assertNull(deprecation.getLink()); - assertEquals(Deprecation.Level.DEFAULT, deprecation.getLevel()); - assertNotNull(deprecation.toString()); - assertEquals(deprecation, new Deprecation(deprecation)); - assertEquals(deprecation.hashCode(), new Deprecation(deprecation).hashCode()); - deprecation = Deprecation.of(SINCE, REPLACEMENT, REASON); + deprecation = of(SINCE, REPLACEMENT, REASON); assertObjectMethods(deprecation); assertEquals(Version.of(SINCE), deprecation.getSince()); assertEquals(REPLACEMENT, deprecation.getReplacement()); assertEquals(REASON, deprecation.getReason()); assertNull(deprecation.getLink()); - assertEquals(Deprecation.Level.DEFAULT, deprecation.getLevel()); + assertEquals(DEFAULT, deprecation.getLevel()); assertNotNull(deprecation.toString()); assertEquals(deprecation, new Deprecation(deprecation)); assertEquals(deprecation.hashCode(), new Deprecation(deprecation).hashCode()); + assertNotEquals(of(SINCE, REPLACEMENT, "Reason"), deprecation); - deprecation = Deprecation.of(SINCE, REPLACEMENT); + + deprecation = of(SINCE, REPLACEMENT); assertObjectMethods(deprecation); assertEquals(Version.of(SINCE), deprecation.getSince()); assertEquals(REPLACEMENT, deprecation.getReplacement()); assertNull(deprecation.getReason()); assertNull(deprecation.getLink()); - assertEquals(Deprecation.Level.DEFAULT, deprecation.getLevel()); + assertEquals(DEFAULT, deprecation.getLevel()); assertNotNull(deprecation.toString()); assertEquals(deprecation, new Deprecation(deprecation)); assertEquals(deprecation.hashCode(), new Deprecation(deprecation).hashCode()); + assertNotEquals(of(SINCE, "Replacement"), deprecation); + - deprecation = Deprecation.of(SINCE); + deprecation = of(SINCE); assertObjectMethods(deprecation); assertEquals(Version.of(SINCE), deprecation.getSince()); assertNull(deprecation.getReplacement()); assertNull(deprecation.getReason()); assertNull(deprecation.getLink()); - assertEquals(Deprecation.Level.DEFAULT, deprecation.getLevel()); + assertEquals(DEFAULT, deprecation.getLevel()); assertNotNull(deprecation.toString()); assertEquals(deprecation, new Deprecation(deprecation)); assertEquals(deprecation.hashCode(), new Deprecation(deprecation).hashCode()); + assertNotEquals(of("1.2.3"), deprecation); } diff --git a/microsphere-java-core/src/test/java/io/microsphere/logging/NoDelegateLoggerFactory.java b/microsphere-java-core/src/test/java/io/microsphere/logging/NoDelegateLoggerFactory.java new file mode 100644 index 000000000..68a81ff43 --- /dev/null +++ b/microsphere-java-core/src/test/java/io/microsphere/logging/NoDelegateLoggerFactory.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.microsphere.logging; + +/** + * No Delegate {@link LoggerFactory} + * + * @author Mercy + * @see LoggerFactory + * @since 1.0.0 + */ +public class NoDelegateLoggerFactory extends LoggerFactory { + + @Override + protected String getDelegateLoggerClassName() { + return "class-not-found"; + } + + @Override + public Logger createLogger(String name) { + return null; + } +} diff --git a/microsphere-java-core/src/test/java/io/microsphere/management/ManagementUtilsTest.java b/microsphere-java-core/src/test/java/io/microsphere/management/ManagementUtilsTest.java index 7f682bc44..bb40748ba 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/management/ManagementUtilsTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/management/ManagementUtilsTest.java @@ -1,14 +1,11 @@ package io.microsphere.management; import io.microsphere.AbstractTestCase; -import io.microsphere.process.ProcessIdResolver; import org.junit.jupiter.api.Test; -import java.util.List; - +import static io.microsphere.management.ManagementUtils.currentProcessId; import static io.microsphere.management.ManagementUtils.getCurrentProcessId; -import static io.microsphere.process.ProcessIdResolver.UNKNOWN_PROCESS_ID; -import static io.microsphere.util.ServiceLoaderUtils.loadServicesList; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; /** @@ -22,16 +19,9 @@ class ManagementUtilsTest extends AbstractTestCase { @Test void testGetCurrentProcessId() { - long currentProcessId = getCurrentProcessId(); - assertTrue(currentProcessId > 0); - } - - @Test - void testLog() { - List resolvers = loadServicesList(ProcessIdResolver.class); - for (ProcessIdResolver resolver : resolvers) { - ManagementUtils.log(resolver, UNKNOWN_PROCESS_ID); - } + long processId = getCurrentProcessId(); + assertTrue(processId > 0); + assertEquals(currentProcessId, getCurrentProcessId()); } -} +} \ No newline at end of file diff --git a/microsphere-java-core/src/test/java/io/microsphere/net/DelegatingURLConnectionTest.java b/microsphere-java-core/src/test/java/io/microsphere/net/DelegatingURLConnectionTest.java index 7cfa84144..b2554b3ed 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/net/DelegatingURLConnectionTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/net/DelegatingURLConnectionTest.java @@ -16,7 +16,6 @@ */ package io.microsphere.net; -import io.microsphere.io.IOUtils; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -27,11 +26,16 @@ import java.util.List; import java.util.Map; +import static io.microsphere.io.IOUtils.copyToString; +import static io.microsphere.net.ServiceLoaderURLStreamHandlerFactory.attach; +import static io.microsphere.net.console.HandlerTest.TEST_CONSOLE_URL; import static java.lang.System.currentTimeMillis; +import static java.lang.System.out; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -96,207 +100,213 @@ void testGetReadTimeout() { @Test void testGetURL() { - assertEquals(url, urlConnection.getURL()); + assertEquals(url, this.urlConnection.getURL()); } @Test void testGetContentLength() { - assertEquals(19, urlConnection.getContentLength()); + assertEquals(19, this.urlConnection.getContentLength()); } @Test void testGetContentLengthLong() { - assertEquals(19, urlConnection.getContentLengthLong()); + assertEquals(19, this.urlConnection.getContentLengthLong()); } @Test void testGetContentType() { - assertEquals("content/unknown", urlConnection.getContentType()); + assertEquals("content/unknown", this.urlConnection.getContentType()); } @Test void testGetContentEncoding() { - assertNull(urlConnection.getContentEncoding()); + assertNull(this.urlConnection.getContentEncoding()); } @Test void testGetExpiration() { - assertEquals(0, urlConnection.getExpiration()); + assertEquals(0, this.urlConnection.getExpiration()); } @Test void testGetDate() { - assertEquals(0, urlConnection.getDate()); + assertEquals(0, this.urlConnection.getDate()); } @Test void testGetLastModified() { - assertFalse(urlConnection.getLastModified() > currentTimeMillis()); + assertFalse(this.urlConnection.getLastModified() > currentTimeMillis()); } @Test void testGetHeaderField() { - assertNull(urlConnection.getHeaderField(NOT_EXISTS_HEADER_NAME)); - assertEquals("19", urlConnection.getHeaderField(CONTENT_LENGTH_HEADER_NAME)); - assertNotNull(urlConnection.getHeaderField(LAST_MODIFIED_HEADER_NAME)); + assertNull(this.urlConnection.getHeaderField(NOT_EXISTS_HEADER_NAME)); + assertEquals("19", this.urlConnection.getHeaderField(CONTENT_LENGTH_HEADER_NAME)); + assertNotNull(this.urlConnection.getHeaderField(LAST_MODIFIED_HEADER_NAME)); } @Test void testGetHeaderFields() { - assertNotNull(urlConnection.getHeaderFields()); + assertNotNull(this.urlConnection.getHeaderFields()); } @Test void testGetHeaderFieldInt() { - assertEquals(19, urlConnection.getHeaderFieldInt(CONTENT_LENGTH_HEADER_NAME, 10)); - assertEquals(1, urlConnection.getHeaderFieldInt(NOT_EXISTS_HEADER_NAME, 1)); + assertEquals(19, this.urlConnection.getHeaderFieldInt(CONTENT_LENGTH_HEADER_NAME, 10)); + assertEquals(1, this.urlConnection.getHeaderFieldInt(NOT_EXISTS_HEADER_NAME, 1)); } @Test void testGetHeaderFieldLong() { - assertEquals(19, urlConnection.getHeaderFieldLong(CONTENT_LENGTH_HEADER_NAME, 10)); - assertEquals(1, urlConnection.getHeaderFieldLong(NOT_EXISTS_HEADER_NAME, 1)); + assertEquals(19, this.urlConnection.getHeaderFieldLong(CONTENT_LENGTH_HEADER_NAME, 10)); + assertEquals(1, this.urlConnection.getHeaderFieldLong(NOT_EXISTS_HEADER_NAME, 1)); } @Test void testGetHeaderFieldDate() { long now = currentTimeMillis(); - assertTrue(now > urlConnection.getHeaderFieldDate(LAST_MODIFIED_HEADER_NAME, now)); - assertEquals(now, urlConnection.getHeaderFieldDate(NOT_EXISTS_HEADER_NAME, now)); + assertTrue(now > this.urlConnection.getHeaderFieldDate(LAST_MODIFIED_HEADER_NAME, now)); + assertEquals(now, this.urlConnection.getHeaderFieldDate(NOT_EXISTS_HEADER_NAME, now)); } @Test void testGetHeaderFieldKey() { - assertEquals(CONTENT_LENGTH_HEADER_NAME, urlConnection.getHeaderFieldKey(0)); - assertEquals(LAST_MODIFIED_HEADER_NAME, urlConnection.getHeaderFieldKey(1)); - assertNull(urlConnection.getHeaderFieldKey(2)); + assertEquals(CONTENT_LENGTH_HEADER_NAME, this.urlConnection.getHeaderFieldKey(0)); + assertEquals(LAST_MODIFIED_HEADER_NAME, this.urlConnection.getHeaderFieldKey(1)); + assertNull(this.urlConnection.getHeaderFieldKey(2)); } @Test void testGetHeaderFieldWithInt() { - assertEquals("19", urlConnection.getHeaderField(0)); - assertNotNull(urlConnection.getHeaderField(1)); - assertNull(urlConnection.getHeaderFieldKey(2)); + assertEquals("19", this.urlConnection.getHeaderField(0)); + assertNotNull(this.urlConnection.getHeaderField(1)); + assertNull(this.urlConnection.getHeaderFieldKey(2)); } @Test void testGetContent() throws IOException { - urlConnection.getContent(); + this.urlConnection.getContent(); } @Test void testGetContentWithClassArray() throws IOException { - urlConnection.getContent(new Class[0]); + this.urlConnection.getContent(new Class[0]); } @Test void testGetPermission() throws IOException { - assertNotNull(urlConnection.getPermission()); + assertNotNull(this.urlConnection.getPermission()); } @Test void testGetInputStream() throws Exception { String encoding = "UTF-8"; String data = "name = 测试名称"; - assertEquals(data, IOUtils.toString(urlConnection.getInputStream(), encoding)); + assertEquals(data, copyToString(this.urlConnection.getInputStream(), encoding)); } @Test - void testGetOutputStream() throws Exception { - assertThrows(Exception.class, urlConnection::getOutputStream); + void testGetOutputStream() throws IOException { + assertThrows(Exception.class, this.urlConnection::getOutputStream); + + attach(); + URL url = new URL(TEST_CONSOLE_URL); + URLConnection delegate = url.openConnection(); + this.urlConnection = new DelegatingURLConnection(delegate); + assertSame(out, this.urlConnection.getOutputStream()); } @Test void testToString() { - assertNotNull(urlConnection.toString()); + assertNotNull(this.urlConnection.toString()); } @Test void testSetDoInput() { - urlConnection.setDoInput(true); + this.urlConnection.setDoInput(true); } @Test void testGetDoInput() { testSetDoInput(); - assertTrue(urlConnection.getDoInput()); + assertTrue(this.urlConnection.getDoInput()); } @Test void testSetDoOutput() { - urlConnection.setDoOutput(true); + this.urlConnection.setDoOutput(true); } @Test void testGetDoOutput() { testSetDoOutput(); - assertTrue(urlConnection.getDoOutput()); + assertTrue(this.urlConnection.getDoOutput()); } @Test void testSetAllowUserInteraction() { - urlConnection.setAllowUserInteraction(true); + this.urlConnection.setAllowUserInteraction(true); } @Test void testGetAllowUserInteraction() { testSetAllowUserInteraction(); - assertTrue(urlConnection.getAllowUserInteraction()); + assertTrue(this.urlConnection.getAllowUserInteraction()); } @Test void testSetUseCaches() { - urlConnection.setUseCaches(true); + this.urlConnection.setUseCaches(true); } @Test void testGetUseCaches() { testSetUseCaches(); - assertTrue(urlConnection.getUseCaches()); + assertTrue(this.urlConnection.getUseCaches()); } @Test void testSetIfModifiedSince() { long now = currentTimeMillis(); - urlConnection.setIfModifiedSince(now); + this.urlConnection.setIfModifiedSince(now); } @Test void testGetIfModifiedSince() { testSetIfModifiedSince(); - assertTrue(currentTimeMillis() >= urlConnection.getIfModifiedSince()); + assertTrue(currentTimeMillis() >= this.urlConnection.getIfModifiedSince()); } @Test void testSetDefaultUseCaches() { - urlConnection.setDefaultUseCaches(true); + this.urlConnection.setDefaultUseCaches(true); } @Test void testGetDefaultUseCaches() { - urlConnection.setDefaultUseCaches(true); - assertTrue(urlConnection.getDefaultUseCaches()); + this.urlConnection.setDefaultUseCaches(true); + assertTrue(this.urlConnection.getDefaultUseCaches()); } @Test void testSetRequestProperty() { - urlConnection.setRequestProperty("key-1", "value-1"); + this.urlConnection.setRequestProperty("key-1", "value-1"); } @Test void testAddRequestProperty() { - urlConnection.addRequestProperty("key-1", "value-1-1"); - urlConnection.addRequestProperty("key-2", "value-2"); + this.urlConnection.addRequestProperty("key-1", "value-1-1"); + this.urlConnection.addRequestProperty("key-2", "value-2"); } @Test void testGetRequestProperty() { - assertNull(urlConnection.getRequestProperty("key-1")); + assertNull(this.urlConnection.getRequestProperty("key-1")); } @Test void testGetRequestProperties() { - Map> requestProperties = urlConnection.getRequestProperties(); + Map> requestProperties = this.urlConnection.getRequestProperties(); assertNotNull(requestProperties); } } diff --git a/microsphere-java-core/src/test/java/io/microsphere/net/StandardURLStreamHandlerFactoryTest.java b/microsphere-java-core/src/test/java/io/microsphere/net/StandardURLStreamHandlerFactoryTest.java new file mode 100644 index 000000000..527850016 --- /dev/null +++ b/microsphere-java-core/src/test/java/io/microsphere/net/StandardURLStreamHandlerFactoryTest.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.microsphere.net; + + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/** + * {@link StandardURLStreamHandlerFactory} Test + * + * @author Mercy + * @see StandardURLStreamHandlerFactory + * @since 1.0.0 + */ +class StandardURLStreamHandlerFactoryTest { + + private StandardURLStreamHandlerFactory factory; + + @BeforeEach + void setUp() { + this.factory = new StandardURLStreamHandlerFactory(); + } + + @Test + void testCreateURLStreamHandler() { + assertNotNull(this.factory.createURLStreamHandler("file")); + assertNotNull(this.factory.createURLStreamHandler(null, "file")); + } +} \ No newline at end of file diff --git a/microsphere-java-core/src/test/java/io/microsphere/net/URLUtilsTest.java b/microsphere-java-core/src/test/java/io/microsphere/net/URLUtilsTest.java index c5a442f91..0a240e302 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/net/URLUtilsTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/net/URLUtilsTest.java @@ -25,14 +25,22 @@ import static io.microsphere.collection.MapUtils.newHashMap; import static io.microsphere.constants.FileConstants.CLASS_EXTENSION; import static io.microsphere.constants.PathConstants.SLASH; +import static io.microsphere.constants.PathConstants.SLASH_CHAR; +import static io.microsphere.constants.ProtocolConstants.EAR_PROTOCOL; +import static io.microsphere.constants.ProtocolConstants.FILE_PROTOCOL; import static io.microsphere.constants.ProtocolConstants.FTP_PROTOCOL; import static io.microsphere.constants.ProtocolConstants.HTTP_PROTOCOL; +import static io.microsphere.constants.ProtocolConstants.JAR_PROTOCOL; +import static io.microsphere.constants.ProtocolConstants.WAR_PROTOCOL; +import static io.microsphere.constants.ProtocolConstants.ZIP_PROTOCOL; import static io.microsphere.constants.SymbolConstants.AND_CHAR; import static io.microsphere.constants.SymbolConstants.COLON; +import static io.microsphere.constants.SymbolConstants.COLON_CHAR; import static io.microsphere.constants.SymbolConstants.SPACE; import static io.microsphere.net.URLUtils.FILE_URL_PREFIX; import static io.microsphere.net.URLUtils.attachURLStreamHandlerFactory; import static io.microsphere.net.URLUtils.buildMatrixString; +import static io.microsphere.net.URLUtils.buildPath; import static io.microsphere.net.URLUtils.buildURI; import static io.microsphere.net.URLUtils.clearURLStreamHandlerFactory; import static io.microsphere.net.URLUtils.close; @@ -41,6 +49,7 @@ import static io.microsphere.net.URLUtils.getMutableURLStreamHandlerFactory; import static io.microsphere.net.URLUtils.getSubProtocol; import static io.microsphere.net.URLUtils.getURLStreamHandlerFactory; +import static io.microsphere.net.URLUtils.isArchiveProtocol; import static io.microsphere.net.URLUtils.isArchiveURL; import static io.microsphere.net.URLUtils.isDirectoryURL; import static io.microsphere.net.URLUtils.isJarURL; @@ -53,17 +62,20 @@ import static io.microsphere.net.URLUtils.resolveMatrixParameters; import static io.microsphere.net.URLUtils.resolveParameters; import static io.microsphere.net.URLUtils.resolvePath; +import static io.microsphere.net.URLUtils.resolvePathFromFile; import static io.microsphere.net.URLUtils.resolveProtocol; import static io.microsphere.net.URLUtils.resolveQueryParameters; import static io.microsphere.net.URLUtils.resolveSubProtocols; import static io.microsphere.net.URLUtils.toExternalForm; import static io.microsphere.net.console.HandlerTest.TEST_CONSOLE_URL; +import static io.microsphere.util.ClassLoaderUtils.ResourceType.PACKAGE; import static io.microsphere.util.ClassLoaderUtils.getClassLoader; import static io.microsphere.util.ClassLoaderUtils.getClassResource; import static io.microsphere.util.ClassLoaderUtils.getResource; import static io.microsphere.util.StringUtils.EMPTY_STRING; import static io.microsphere.util.StringUtils.substringBeforeLast; import static io.microsphere.util.SystemUtils.USER_DIR; +import static io.microsphere.util.jar.JarUtils.isDirectoryEntry; import static java.nio.file.Paths.get; import static java.util.Collections.emptyMap; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -96,9 +108,15 @@ class URLUtilsTest extends AbstractTestCase { private static final String TEST_HTTP_WITH_PATH_HASH = TEST_HTTP_WITH_PATH + "#hash"; - private static final String TEST_HTTP_WITH_QUERY_STRING = TEST_HTTP_BASE + "?q=java&oq=java&sourceid=chrome&es_sm=122&ie=UTF-8"; + private static final String TEST_QUERY_STRING = "?q=java&oq=java&sourceid=chrome&es_sm=122&ie=UTF-8"; - private static final String TEST_HTTP_WITH_MATRIX_STRING = TEST_HTTP_BASE + ";q=java;oq=java;sourceid=chrome;es_sm=122;ie=UTF-8"; + private static final String TEST_MATRIX_STRING = ";q=java;oq=java;sourceid=chrome;es_sm=122;ie=UTF-8"; + + private static final String TEST_HTTP_WITH_QUERY_STRING = TEST_HTTP_BASE + TEST_QUERY_STRING; + + private static final String TEST_HTTP_WITH_MATRIX_STRING = TEST_HTTP_BASE + TEST_MATRIX_STRING; + + private static final String TEST_HTTP_WITH_MATRIX_QUERY_STRING = TEST_HTTP_BASE + TEST_MATRIX_STRING + TEST_QUERY_STRING; private static final String TEST_HTTP_WITH_SP_MATRIX = TEST_HTTP_BASE + ";_sp=text;_sp=properties"; @@ -152,7 +170,7 @@ void testResolveBasePathOnFile() { } @Test - void testResolveBasePathOnArchiveEntry() throws MalformedURLException { + void testResolveBasePathOnArchiveEntry() { String basePath = resolveBasePath(classArchiveEntryURL); assertNotNull(basePath); assertTrue(new File(basePath).exists()); @@ -170,6 +188,12 @@ void testResolveArchiveFileOnClassFile() { assertTrue(archiveFile.exists()); } + @Test + void testResolveArchiveFileOnNotFoundJar() { + URL url = ofURL("jar:file:/not-found.jar!/com/acme"); + assertNull(resolveArchiveFile(url)); + } + @Test void testResolveQueryParameters() { String url = TEST_HTTP_WITH_QUERY_STRING; @@ -207,6 +231,10 @@ void testResolveMatrixParameters() { assertEquals(expectedParametersMap, parametersMap); + url = TEST_HTTP_WITH_MATRIX_QUERY_STRING; + parametersMap = resolveMatrixParameters(url); + assertEquals(expectedParametersMap, parametersMap); + url = TEST_HTTP_WITH_QUERY_STRING; parametersMap = resolveMatrixParameters(url); expectedParametersMap = emptyMap(); @@ -285,10 +313,17 @@ void testDecodeOnInvalidEncoding() { } @Test - void testIsDirectoryURL() throws Exception { - URL resourceURL = getClassResource(classLoader, StringUtils.class); + void testIsDirectoryURL() { + assertFalse(isDirectoryURL(null)); + assertFalse(isDirectoryURL(classFileURL)); + URL resourceURL = getClassResource(classLoader, StringUtils.class); + assertFalse(isDirectoryURL(resourceURL)); + + resourceURL = getResource(this.classLoader, PACKAGE, "javax.annotation"); + assertTrue(isDirectoryEntry(resourceURL)); + String externalForm = null; externalForm = substringBeforeLast(resourceURL.toExternalForm(), StringUtils.class.getSimpleName() + CLASS_EXTENSION); resourceURL = ofURL(externalForm); @@ -321,27 +356,57 @@ void testIsJarURLOnArchiveEntry() { } @Test - void testIsJarURLOnArchiveFile() throws MalformedURLException { + void testIsJarURLOnArchiveFile() { File archiveFile = resolveArchiveFile(classArchiveEntryURL); assertTrue(isJarURL(ofURL(FILE_URL_PREFIX + archiveFile.getAbsolutePath()))); } @Test - void testIsArchiveURLOnJar() throws MalformedURLException { + void testIsJarURLOnHttp() { + URL url = ofURL("http://localhost"); + assertFalse(isJarURL(url)); + } + + @Test + void testIsJarURLOnNPE() { + assertThrows(NullPointerException.class, () -> isJarURL(null)); + } + + @Test + void testIsArchiveURLOnJar() { assertTrue(isArchiveURL(classArchiveEntryURL)); } +// +// @Test +// void testIsArchiveURLOnWar() { +// testIsArchiveURL(WAR_PROTOCOL); +// } +// +// @Test +// void testIsArchiveURLOnEar() { +// testIsArchiveURL(EAR_PROTOCOL); +// } @Test - void testIsArchiveURLOnFile() throws MalformedURLException { - File archiveFile = resolveArchiveFile(classArchiveEntryURL); - assertTrue(isArchiveURL(ofURL(FILE_URL_PREFIX + archiveFile.getAbsolutePath()))); + void testIsArchiveURLOnFile() { + testIsArchiveURL(FILE_PROTOCOL); } @Test - void testIsArchiveURLOnNotJar() throws MalformedURLException { + void testIsArchiveURLOnNotJar() { assertFalse(isArchiveURL(classFileURL)); } + @Test + void testIsArchiveProtocol() { + assertTrue(isArchiveProtocol(JAR_PROTOCOL)); + assertTrue(isArchiveProtocol(ZIP_PROTOCOL)); + assertTrue(isArchiveProtocol(WAR_PROTOCOL)); + assertTrue(isArchiveProtocol(EAR_PROTOCOL)); + assertFalse(isArchiveProtocol(FTP_PROTOCOL)); + assertFalse(isArchiveProtocol(FILE_PROTOCOL)); + } + @Test void testBuildURI() { String path = buildURI("a", "b", "c"); @@ -395,26 +460,26 @@ void testToExternalFormOnClassArchiveEntry() { } @Test - void testToExternalFormWithMatrixString() throws MalformedURLException { + void testToExternalFormWithMatrixString() { testToExternalForm(TEST_HTTP_WITH_MATRIX_STRING); } @Test - void testToExternalFormWithQueryString() throws MalformedURLException { + void testToExternalFormWithQueryString() { testToExternalForm(TEST_HTTP_WITH_QUERY_STRING); } @Test - void testToExternalFormWithPath() throws MalformedURLException { + void testToExternalFormWithPath() { testToExternalForm(TEST_HTTP_WITH_PATH); } @Test - void testToExternalFormWithRef() throws MalformedURLException { + void testToExternalFormWithRef() { testToExternalForm(TEST_HTTP_WITH_PATH_HASH); } - private void testToExternalForm(String urlString) throws MalformedURLException { + private void testToExternalForm(String urlString) { testToExternalForm(ofURL(urlString)); } @@ -433,7 +498,7 @@ void testGetSubProtocolWithSubProtocol() { } @Test - void testResolveSubProtocolsFromMatrixString() throws MalformedURLException { + void testResolveSubProtocolsFromMatrixString() { URL url = ofURL(TEST_HTTP_WITH_SP_MATRIX); List subProtocols = resolveSubProtocols(url); assertEquals(2, subProtocols.size()); @@ -442,7 +507,7 @@ void testResolveSubProtocolsFromMatrixString() throws MalformedURLException { } @Test - void testResolveSubProtocolsFromProtocol() throws MalformedURLException { + void testResolveSubProtocolsFromProtocol() { new Handler(); URL url = ofURL("console:text:properties://localhost"); List subProtocols = resolveSubProtocols(url); @@ -471,6 +536,11 @@ void testResolvePath() { assertResolvePath(classPathURL); assertResolvePath(classFileURL); } +// +// @Test +// void testResolvePathWith() { +// assertResolvePath(classArchiveEntryURL, false); +// } @Test void testResolvePathWithMatrixString() { @@ -559,14 +629,47 @@ void testResolveParametersOnEmptyString() { assertSame(emptyMap(), resolveParameters(EMPTY_STRING, AND_CHAR)); } + @Test + void testResolvePathFromFile() { + URL url = ofURL("file:///D:/test"); + assertEquals("D:/test", resolvePathFromFile(url, true)); + + ofURL("file://D:/test"); + assertEquals("D:/test", resolvePathFromFile(url, true)); + + ofURL("file:/D:/test"); + assertEquals("D:/test", resolvePathFromFile(url, true)); + + ofURL("file:test"); + assertEquals("D:/test", resolvePathFromFile(url, true)); + + ofURL("file://D:/test"); + assertEquals("/D:/test", resolvePathFromFile(url, false)); + } + + @Test + void testBuildPath() { + URL url = ofURL("file:///D:/test"); + String path = buildPath(url); + assertEquals(url.getPath(), path); + + url = ofURL("file:"); + path = buildPath(url); + assertEquals(url.getPath(), path); + } private void assertResolvePath(URL url) { assertResolvePath(url, true); } private void assertResolvePath(URL url, boolean includeArchiveEntryPath) { - String path = URLUtils.resolvePath(url, includeArchiveEntryPath); + String path = resolvePath(url, includeArchiveEntryPath); assertEquals(new File(path), new File(url.getPath())); } + void testIsArchiveURL(String protocol) { + File archiveFile = resolveArchiveFile(classArchiveEntryURL); + assertTrue(isArchiveURL(ofURL(protocol + COLON_CHAR + SLASH_CHAR + archiveFile.getAbsolutePath()))); + } + } diff --git a/microsphere-java-core/src/test/java/io/microsphere/process/ProcessExecutorTest.java b/microsphere-java-core/src/test/java/io/microsphere/process/ProcessExecutorTest.java index ca4892f90..557aa516d 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/process/ProcessExecutorTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/process/ProcessExecutorTest.java @@ -1,15 +1,15 @@ package io.microsphere.process; import io.microsphere.AbstractTestCase; +import io.microsphere.io.FastByteArrayOutputStream; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.concurrent.TimeoutException; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -22,42 +22,43 @@ */ class ProcessExecutorTest extends AbstractTestCase { - private ProcessExecutor executor; + private FastByteArrayOutputStream outputStream; @BeforeEach void setUp() { - this.executor = new ProcessExecutor("java", "-version"); + this.outputStream = new FastByteArrayOutputStream(8 * 1024); } - @Test - void testIsFinished() throws Exception { - assertFalse(this.executor.isFinished()); + @AfterEach + void tearDown() { + this.outputStream.close(); } @Test void testExecute() throws Exception { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(8 * 1024); - this.executor.execute(outputStream); - assertTrue(outputStream.size() > 0); - assertTrue(this.executor.isFinished()); - String response = new String(outputStream.toByteArray()); + ProcessExecutor processExecutor = new ProcessExecutor("java", "-version"); + processExecutor.execute(this.outputStream); + assertTrue(this.outputStream.size() > 0); + String response = this.outputStream.toString(); log(response); } @Test void testExecuteWithTimeout() { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(8 * 1024); - assertThrows(TimeoutException.class, () -> this.executor.execute(outputStream, 1)); - assertEquals(0, outputStream.size()); - assertTrue(this.executor.isFinished()); + ProcessExecutor processExecutor = new ProcessExecutor("javac", "--help"); + assertThrows(TimeoutException.class, () -> processExecutor.execute(this.outputStream, 1)); + assertEquals(0, this.outputStream.size()); } @Test - void testExecuteOnWrongCommand() { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(8 * 1024); - ProcessExecutor processExecutor = new ProcessExecutor("ttttt"); - assertThrows(IOException.class, () -> processExecutor.execute(outputStream)); - assertFalse(processExecutor.isFinished()); + void testExecuteOnFailed() { + ProcessExecutor processExecutor = new ProcessExecutor("javac", "-a"); + assertThrows(IOException.class, () -> processExecutor.execute(this.outputStream)); } -} + @Test + void testExecuteOnNotFoundCommand() { + ProcessExecutor processExecutor = new ProcessExecutor("not-found-command"); + assertThrows(IOException.class, () -> processExecutor.execute(this.outputStream)); + } +} \ No newline at end of file diff --git a/microsphere-java-core/src/test/java/io/microsphere/process/ProcessManagerTest.java b/microsphere-java-core/src/test/java/io/microsphere/process/ProcessManagerTest.java index d136b1a78..445ecffc3 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/process/ProcessManagerTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/process/ProcessManagerTest.java @@ -1,6 +1,7 @@ package io.microsphere.process; import io.microsphere.AbstractTestCase; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.io.ByteArrayOutputStream; @@ -24,8 +25,13 @@ */ class ProcessManagerTest extends AbstractTestCase { + @BeforeEach + void setUp() { + INSTANCE.unfinishedProcessesCache.clear(); + } + @Test - void test() throws Throwable { + void test() { ProcessManager processManager = INSTANCE; ProcessExecutor processExecutor = new ProcessExecutor("java", "-version"); ExecutorService executorService = newFixedThreadPool(1); @@ -34,7 +40,7 @@ void test() throws Throwable { long timeout = timeUnit.toMillis(2); Future future = executorService.submit(() -> { processExecutor.execute(outputStream, timeout); - return processExecutor.isFinished(); + return true; }); while (!future.isDone()) { diff --git a/microsphere-java-core/src/test/java/io/microsphere/reflect/AbstractReflectiveDefinitionTest.java b/microsphere-java-core/src/test/java/io/microsphere/reflect/AbstractReflectiveDefinitionTest.java index f16864350..fb87a8127 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/reflect/AbstractReflectiveDefinitionTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/reflect/AbstractReflectiveDefinitionTest.java @@ -12,6 +12,7 @@ import static io.microsphere.lang.DeprecationTest.DEPRECATION; import static io.microsphere.lang.DeprecationTest.SINCE; import static io.microsphere.reflect.ConstructorUtils.findConstructor; +import static io.microsphere.util.ArrayUtils.ofArray; import static io.microsphere.util.Version.ofVersion; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -30,12 +31,13 @@ */ public abstract class AbstractReflectiveDefinitionTest { - private final List[] headConstructorArgumentsArray = new List[]{ + private final List[] headConstructorArgumentsArray = ofArray( ofList(SINCE, getClassName()), ofList(ofVersion(SINCE), getClassName()), ofList(SINCE, DEPRECATION, getClassName()), - ofList(ofVersion(SINCE), DEPRECATION, getClassName()) - }; + ofList(ofVersion(SINCE), DEPRECATION, getClassName()), + ofList(ofVersion("2.0.0"), DEPRECATION, getClassName()) + ); protected List definitions; @@ -85,6 +87,7 @@ void testGetDeprecation() { assertNull(definitions.get(1).getDeprecation()); assertNotNull(definitions.get(2).getDeprecation()); assertNotNull(definitions.get(3).getDeprecation()); + assertNotNull(definitions.get(4).getDeprecation()); } @Test @@ -98,6 +101,7 @@ void testGetClassName() { void testGetResolvedClass() { for (D definition : definitions) { assertNotNull(definition.getResolvedClass()); + assertNotNull(definition.getResolvedClass()); } } @@ -107,6 +111,7 @@ void testIsDeprecated() { assertFalse(definitions.get(1).isDeprecated()); assertTrue(definitions.get(2).isDeprecated()); assertTrue(definitions.get(3).isDeprecated()); + assertTrue(definitions.get(4).isDeprecated()); } @Test @@ -118,9 +123,13 @@ void testIsPresent() { @Test void testTestEquals() { + assertEquals(definitions.get(0), definitions.get(0)); assertEquals(definitions.get(0), definitions.get(1)); assertEquals(definitions.get(2), definitions.get(3)); assertNotEquals(definitions.get(0), definitions.get(2)); + assertNotEquals(definitions.get(0), definitions.get(2)); + assertNotEquals(definitions.get(0), definitions.get(4)); + assertFalse(definitions.get(0).equals(this)); } @Test @@ -128,6 +137,7 @@ void testTestHashCode() { assertEquals(definitions.get(0).hashCode(), definitions.get(1).hashCode()); assertEquals(definitions.get(2).hashCode(), definitions.get(3).hashCode()); assertNotEquals(definitions.get(0).hashCode(), definitions.get(2).hashCode()); + assertNotEquals(definitions.get(0).hashCode(), definitions.get(4).hashCode()); } @Test @@ -135,5 +145,6 @@ void testTestToString() { assertEquals(definitions.get(0).toString(), definitions.get(1).toString()); assertEquals(definitions.get(2).toString(), definitions.get(3).toString()); assertNotEquals(definitions.get(0).toString(), definitions.get(2).toString()); + assertNotEquals(definitions.get(0).toString(), definitions.get(4).toString()); } } \ No newline at end of file diff --git a/microsphere-java-core/src/test/java/io/microsphere/reflect/AccessibleObjectUtilsTest.java b/microsphere-java-core/src/test/java/io/microsphere/reflect/AccessibleObjectUtilsTest.java index 57a4e007e..18e4bc7d2 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/reflect/AccessibleObjectUtilsTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/reflect/AccessibleObjectUtilsTest.java @@ -24,13 +24,16 @@ import java.lang.reflect.Method; import static io.microsphere.reflect.AccessibleObjectUtils.canAccess; +import static io.microsphere.reflect.AccessibleObjectUtils.handleInaccessibleObjectExceptionIfFound; import static io.microsphere.reflect.AccessibleObjectUtils.setAccessible; +import static io.microsphere.reflect.AccessibleObjectUtils.tryCanAccess; import static io.microsphere.reflect.AccessibleObjectUtils.trySetAccessible; import static io.microsphere.reflect.ConstructorUtils.findConstructor; import static io.microsphere.reflect.MemberUtils.isStatic; import static io.microsphere.reflect.MethodUtils.findMethod; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; /** @@ -84,6 +87,10 @@ void testCanAccess() { @Test void testCanAccessOnNonPublicMembers() { assertFalse(canAccess(null, tryCanAccessMethod)); + + Method cloneMethod = findMethod(Object.class, "clone"); + assertFalse(canAccess(null, cloneMethod)); + assertFalse(canAccess(test, cloneMethod)); } @Test @@ -98,4 +105,20 @@ void testTrySetAccessibleOnNonPublicMembers() { assertTrue(trySetAccessible(tryCanAccessMethod)); assertTrue(trySetAccessible(abstractProcessorConstructor)); } -} + + @Test + void testTrySetAccessibleOnFailed() { + assertFalse(trySetAccessible(null, null)); + } + + @Test + void testTryCanAccessOnFailed() { + assertNull(tryCanAccess(null, null)); + assertNull(tryCanAccess(null, null, null)); + } + + @Test + void testHandleInaccessibleObjectExceptionIfFound() { + handleInaccessibleObjectExceptionIfFound(new RuntimeException("For testing")); + } +} \ No newline at end of file diff --git a/microsphere-java-core/src/test/java/io/microsphere/reflect/FieldUtilsTest.java b/microsphere-java-core/src/test/java/io/microsphere/reflect/FieldUtilsTest.java index cb2e503fd..27be787b9 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/reflect/FieldUtilsTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/reflect/FieldUtilsTest.java @@ -107,6 +107,15 @@ void testFindFieldOnPredicate() { assertFindField(ReflectionTest.class, "staticField", false); } + @Test + void testFindFieldsOnNull() { + assertNull(findField(null, null)); + } + + @Test + void testFindFieldsOnObjectClass() { + assertNull(findField(Object.class, null)); + } @Test void testFindAllFields() { @@ -200,11 +209,17 @@ void testGetFieldValueOnIllegalArgumentException() { assertThrows(IllegalArgumentException.class, () -> getFieldValue("test", field)); } + @Test + void testGetFieldValueOnNull() { + Object fieldValue = getFieldValue(null, (Field) null); + assertNull(fieldValue); + } + @Test void testSetFieldValue() { Integer value = 999; setFieldValue(value, "value", 2); - assertEquals(value.intValue(), 2); + assertEquals(value.intValue(), setFieldValue(value, "value", 2)); assertSetFieldValue(test, "privateField", "test"); assertSetFieldValue(test, "packagePrivateField", "test"); @@ -274,6 +289,7 @@ private void assertGetStaticFieldValue(Class klass, String fieldName) { private void assertGetFieldValue(ReflectionTest test, String fieldName) { assertEquals(fieldName, getFieldValue(test, fieldName)); + assertEquals(fieldName, getFieldValue(test, fieldName, (Object) null)); } private void assertGetFieldValue(ReflectionTest test, String fieldName, Object defaultValue) { diff --git a/microsphere-java-core/src/test/java/io/microsphere/reflect/MethodDefinitionTest.java b/microsphere-java-core/src/test/java/io/microsphere/reflect/MethodDefinitionTest.java index 7267473fb..18eaf093a 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/reflect/MethodDefinitionTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/reflect/MethodDefinitionTest.java @@ -17,12 +17,12 @@ package io.microsphere.reflect; import io.microsphere.logging.Logger; -import io.microsphere.logging.LoggerFactory; import org.junit.jupiter.api.Test; import java.util.List; import static io.microsphere.collection.Lists.ofList; +import static io.microsphere.logging.LoggerFactory.getLogger; import static io.microsphere.util.ArrayUtils.ofArray; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; @@ -36,7 +36,7 @@ */ class MethodDefinitionTest extends AbstractExecutableDefinitionTest { - private static final Logger logger = LoggerFactory.getLogger(MethodDefinitionTest.class); + private static final Logger logger = getLogger(MethodDefinitionTest.class); @Override protected List getTailConstructorArguments() { diff --git a/microsphere-java-core/src/test/java/io/microsphere/reflect/MultipleTypeTest.java b/microsphere-java-core/src/test/java/io/microsphere/reflect/MultipleTypeTest.java index 90e054b21..94bab70b8 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/reflect/MultipleTypeTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/reflect/MultipleTypeTest.java @@ -6,7 +6,9 @@ import static io.microsphere.reflect.MultipleType.of; import static java.util.Objects.hash; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * {@link MultipleType} Test @@ -25,18 +27,20 @@ void setUp() { @Test void testHashCode() { - assertEquals(hash(String.class, Object.class), multipleType.hashCode()); + assertEquals(hash(String.class, Object.class), this.multipleType.hashCode()); } @Test void testEquals() { - assertEquals(of(String.class, Object.class), multipleType); + assertTrue(this.multipleType.equals(this.multipleType)); + assertFalse(this.multipleType.equals(null)); + assertEquals(of(String.class, Object.class), this.multipleType); assertEquals(of(String.class, Object.class, Integer.class), of(String.class, Object.class, Integer.class)); - assertNotEquals(of(String.class, Object.class, Integer.class), multipleType); + assertNotEquals(of(String.class, Object.class, Integer.class), this.multipleType); } @Test void testToString() { - assertEquals("MultipleType : [class java.lang.String, class java.lang.Object]", multipleType.toString()); + assertEquals("MultipleType : [class java.lang.String, class java.lang.Object]", this.multipleType.toString()); } } \ No newline at end of file diff --git a/microsphere-java-core/src/test/java/io/microsphere/reflect/ReflectionUtilsTest.java b/microsphere-java-core/src/test/java/io/microsphere/reflect/ReflectionUtilsTest.java index 9087a231b..6d8c42b7b 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/reflect/ReflectionUtilsTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/reflect/ReflectionUtilsTest.java @@ -1,24 +1,33 @@ package io.microsphere.reflect; import io.microsphere.AbstractTestCase; +import io.microsphere.test.Data; import org.junit.jupiter.api.Test; import java.util.HashMap; import java.util.List; import java.util.Map; +import static io.microsphere.collection.Lists.ofList; +import static io.microsphere.reflect.ReflectionUtils.INACCESSIBLE_OBJECT_EXCEPTION_CLASS; +import static io.microsphere.reflect.ReflectionUtils.INACCESSIBLE_OBJECT_EXCEPTION_CLASS_NAME; import static io.microsphere.reflect.ReflectionUtils.getCallerClass; import static io.microsphere.reflect.ReflectionUtils.getCallerClassInGeneralJVM; import static io.microsphere.reflect.ReflectionUtils.getCallerClassInSunJVM; import static io.microsphere.reflect.ReflectionUtils.getCallerClassName; import static io.microsphere.reflect.ReflectionUtils.getCallerClassNameInGeneralJVM; import static io.microsphere.reflect.ReflectionUtils.getCallerClassNameInSunJVM; +import static io.microsphere.reflect.ReflectionUtils.isInaccessibleObjectException; import static io.microsphere.reflect.ReflectionUtils.isSupportedSunReflectReflection; import static io.microsphere.reflect.ReflectionUtils.readFieldsAsMap; import static io.microsphere.reflect.ReflectionUtils.toList; +import static io.microsphere.reflect.ReflectionUtils.toObject; +import static io.microsphere.util.ArrayUtils.ofArray; import static java.util.Arrays.asList; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * {@link ReflectionUtils} Test @@ -30,7 +39,7 @@ class ReflectionUtilsTest extends AbstractTestCase { @Test - void testGetCallerClassX() throws Exception { + void testGetCallerClassX() { Class expectedClass = ReflectionUtilsTest.class; Class callerClass = getCallerClass(); @@ -90,5 +99,36 @@ void testReadFieldsAsMap() { value.put("c", "c"); map = readFieldsAsMap(value); assertFalse(map.isEmpty()); + + T t = new T(); + t.self = t; + t.other = new T(); + + map = readFieldsAsMap(t); + assertFalse(map.isEmpty()); + } + + @Test + void testToObject() { + assertNull(toObject(null)); + assertEquals("test", toObject("test")); + assertEquals(ofList("a", "b", "c"), toObject(ofArray("a", "b", "c"))); + } + + @Test + void testIsInaccessibleObjectException() { + assertFalse(isInaccessibleObjectException(new RuntimeException())); + assertFalse(isInaccessibleObjectException((Throwable) null)); + assertFalse(isInaccessibleObjectException((Class) null)); + assertFalse(isInaccessibleObjectException(Class.class)); + assertEquals(INACCESSIBLE_OBJECT_EXCEPTION_CLASS != null, isInaccessibleObjectException(INACCESSIBLE_OBJECT_EXCEPTION_CLASS)); + assertTrue(isInaccessibleObjectException(INACCESSIBLE_OBJECT_EXCEPTION_CLASS_NAME)); + } + + static class T extends Data { + + private T self; + + private T other; } } diff --git a/microsphere-java-core/src/test/java/io/microsphere/reflect/ReflectiveDefinitionTest.java b/microsphere-java-core/src/test/java/io/microsphere/reflect/ReflectiveDefinitionTest.java new file mode 100644 index 000000000..13cdee6ac --- /dev/null +++ b/microsphere-java-core/src/test/java/io/microsphere/reflect/ReflectiveDefinitionTest.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.microsphere.reflect; + + +import org.junit.jupiter.api.Test; + +/** + * {@link ReflectiveDefinition} Test + * + * @author Mercy + * @see ReflectiveDefinition + * @since 1.0.0 + */ +class ReflectiveDefinitionTest { + + @Test + void testGetSince() { + } + + @Test + void testGetDeprecation() { + } + + @Test + void testGetClassName() { + } + + @Test + void testGetResolvedClass() { + } + + @Test + void testIsDeprecated() { + } + + @Test + void testIsPresent() { + } + + @Test + void testTestEquals() { + } + + @Test + void testTestHashCode() { + } + + @Test + void testTestToString() { + } +} \ No newline at end of file diff --git a/microsphere-java-core/src/test/java/io/microsphere/util/ClassPathUtilsTest.java b/microsphere-java-core/src/test/java/io/microsphere/util/ClassPathUtilsTest.java index af755538b..bdfc5c3a1 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/util/ClassPathUtilsTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/util/ClassPathUtilsTest.java @@ -4,13 +4,14 @@ package io.microsphere.util; import io.microsphere.AbstractTestCase; -import io.microsphere.lang.ClassDataRepository; import org.junit.jupiter.api.Test; import java.lang.management.RuntimeMXBean; import java.net.URL; import java.util.Set; +import java.util.function.Predicate; +import static io.microsphere.lang.ClassDataRepository.INSTANCE; import static io.microsphere.util.ClassLoaderUtils.isLoadedClass; import static io.microsphere.util.ClassPathUtils.getBootstrapClassPaths; import static io.microsphere.util.ClassPathUtils.getClassPaths; @@ -57,16 +58,22 @@ void testGetRuntimeClassLocation() { assertNotNull(location); log(location); - //Primitive type + // Primitive type location = getRuntimeClassLocation(int.class); assertNull(location); - //Array type + // Array type location = getRuntimeClassLocation(int[].class); assertNull(location); + // Synthetic type + Predicate predicate = t -> true; + predicate = predicate.negate(); + location = getRuntimeClassLocation(predicate.getClass()); + assertNull(location); + - Set classNames = ClassDataRepository.INSTANCE.getAllClassNamesInClassPaths(); + Set classNames = INSTANCE.getAllClassNamesInClassPaths(); for (String className : classNames) { if (!isLoadedClass(TEST_CLASS_LOADER, className)) { location = getRuntimeClassLocation(className); diff --git a/microsphere-java-core/src/test/java/io/microsphere/util/ClassUtilsTest.java b/microsphere-java-core/src/test/java/io/microsphere/util/ClassUtilsTest.java index d1a9f2441..9174d67d4 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/util/ClassUtilsTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/util/ClassUtilsTest.java @@ -5,6 +5,7 @@ import io.microsphere.AbstractTestCase; import io.microsphere.lang.ClassDataRepository; +import io.microsphere.test.A; import org.junit.jupiter.api.Test; import javax.annotation.Nonnull; @@ -13,6 +14,7 @@ import java.lang.reflect.Array; import java.math.BigDecimal; import java.math.BigInteger; +import java.net.URL; import java.nio.CharBuffer; import java.util.AbstractCollection; import java.util.AbstractMap; @@ -26,7 +28,9 @@ import java.util.TreeMap; import java.util.concurrent.TimeUnit; import java.util.function.BiFunction; +import java.util.function.Predicate; +import static io.microsphere.collection.Lists.ofList; import static io.microsphere.collection.MapUtils.ofEntry; import static io.microsphere.constants.SymbolConstants.SPACE; import static io.microsphere.util.ArrayUtils.EMPTY_BOOLEAN_ARRAY; @@ -40,16 +44,23 @@ import static io.microsphere.util.ArrayUtils.EMPTY_OBJECT_ARRAY; import static io.microsphere.util.ArrayUtils.EMPTY_SHORT_ARRAY; import static io.microsphere.util.ArrayUtils.ofArray; +import static io.microsphere.util.ClassLoaderUtils.getResource; import static io.microsphere.util.ClassUtils.ARRAY_SUFFIX; import static io.microsphere.util.ClassUtils.PRIMITIVE_TYPES; import static io.microsphere.util.ClassUtils.arrayTypeEquals; import static io.microsphere.util.ClassUtils.cast; import static io.microsphere.util.ClassUtils.concreteClassCache; import static io.microsphere.util.ClassUtils.findAllClasses; +import static io.microsphere.util.ClassUtils.findClassNamesInClassPath; +import static io.microsphere.util.ClassUtils.findClassNamesInJarFile; import static io.microsphere.util.ClassUtils.getAllClasses; +import static io.microsphere.util.ClassUtils.getAllInheritedTypes; import static io.microsphere.util.ClassUtils.getAllInterfaces; import static io.microsphere.util.ClassUtils.getAllSuperClasses; import static io.microsphere.util.ClassUtils.getClasses; +import static io.microsphere.util.ClassUtils.getCodeSource; +import static io.microsphere.util.ClassUtils.getCodeSourceLocation; +import static io.microsphere.util.ClassUtils.getProtectionDomain; import static io.microsphere.util.ClassUtils.getSimpleName; import static io.microsphere.util.ClassUtils.getTopComponentType; import static io.microsphere.util.ClassUtils.getType; @@ -57,6 +68,7 @@ import static io.microsphere.util.ClassUtils.getTypes; import static io.microsphere.util.ClassUtils.isAbstractClass; import static io.microsphere.util.ClassUtils.isArray; +import static io.microsphere.util.ClassUtils.isAsciiDigit; import static io.microsphere.util.ClassUtils.isAssignableFrom; import static io.microsphere.util.ClassUtils.isCharSequence; import static io.microsphere.util.ClassUtils.isClass; @@ -77,12 +89,14 @@ import static io.microsphere.util.ClassUtils.resolvePrimitiveType; import static io.microsphere.util.ClassUtils.resolveWrapperType; import static io.microsphere.util.ClassUtils.tryResolveWrapperType; +import static java.lang.Integer.valueOf; import static java.lang.Thread.State.NEW; import static java.util.Collections.emptyList; import static java.util.Collections.emptySet; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -179,6 +193,9 @@ void testIsGeneralClass() { assertFalse(isGeneralClass(Override.class)); // test enum assertFalse(isGeneralClass(TimeUnit.class)); + // test synthetic + Predicate p = a -> true; + assertFalse(isGeneralClass(p.negate().getClass())); // test primitive assertFalse(isGeneralClass(int.class)); // test array @@ -440,6 +457,11 @@ void testIsWrapperType() { assertFalse(isWrapperType(null)); } + @Test + void testIsWrapperTypeWithObject() { + assertTrue(isWrapperType(valueOf(1))); + } + @Test void testArrayTypeEquals() { assertFalse(arrayTypeEquals(null, null)); @@ -491,9 +513,26 @@ void testResolvePackageNameOnPrimitiveType() { } @Test - void testFindClassNamesInClassPath() { + void testFindClassNamesInClassPathWithFilePath() throws Exception { assertFindClassNamesMethod(ClassUtilsTest.class, ClassUtils::findClassNamesInClassPath); assertFindClassNamesMethod(Nonnull.class, ClassUtils::findClassNamesInClassPath); + + File tempFile = createRandomTempFile(); + assertTrue(findClassNamesInClassPath(tempFile, true).isEmpty()); + assertTrue(findClassNamesInClassPath(tempFile, false).isEmpty()); + + + File link = makeLinkFile(tempFile); + assertTrue(findClassNamesInClassPath(link, false).isEmpty()); + } + + @Test + void testFindClassNamesInClassPathWithStringPath() { + URL location = getCodeSourceLocation(Nonnull.class); + assertFindClassNamesInClassPath(location); + + location = getResource("javax/annotation/Nonnull.class"); + assertFindClassNamesInClassPath(location); } @Test @@ -506,9 +545,31 @@ void testFindClassNamesInJarFile() { assertFindClassNamesMethod(Nonnull.class, ClassUtils::findClassNamesInJarFile); } + @Test + void testFindClassNamesInEmptyJarFile() { + URL resource = getResource("META-INF/empty.sar"); + File emptyJarFile = new File(resource.getFile()); + assertTrue(findClassNamesInJarFile(emptyJarFile, true).isEmpty()); + assertTrue(findClassNamesInJarFile(emptyJarFile, false).isEmpty()); + } + + @Test + void testFindClassNamesInEmptyClassNameJarFile() { + URL resource = getResource("META-INF/empty-class-name.sar"); + File emptyClassNameJarFile = new File(resource.getFile()); + assertTrue(findClassNamesInJarFile(emptyClassNameJarFile, true).isEmpty()); + assertTrue(findClassNamesInJarFile(emptyClassNameJarFile, false).isEmpty()); + } + @Test void testResolveClassName() { assertEquals("java.lang.String", resolveClassName("java/lang/String.class")); + assertEquals("java.lang.String", resolveClassName("/java/lang/String.class")); + } + + @Test + void testResolveClassNameOnNull() { + assertNull(resolveClassName(null)); } @Test @@ -537,6 +598,17 @@ void testGetAllInterfaces() { assertSame(emptyList(), getAllInterfaces(int.class)); } + @Test + void testGetAllInheritedTypes() { + List> types = getAllInheritedTypes(A.class); + assertEquals(ofList(Object.class, Serializable.class), types); + } + + @Test + void testGetAllInheritedTypesOnNull() { + assertEquals(emptyList(), getAllInheritedTypes(null)); + } + @Test void testGetAllClasses() { List> allClasses = getAllClasses(Object.class); @@ -697,6 +769,32 @@ class LocalClass { assertEquals("double[]", getSimpleName(double[].class)); } + @Test + void testGetSimpleNameOnNull() { + assertNull(getSimpleName(null)); + } + + @Test + void testGetSimpleNameOnMalformedClassName() { + assertThrows(InternalError.class, () -> getSimpleName(Thread.State.class, "java.lang.Thread")); + assertThrows(InternalError.class, () -> getSimpleName(Thread.State.class, "java.lang.Thread.")); + } + + @Test + void testIsAsciiDigit() { + for (int i = 0; i <= 9; i++) { + assertTrue(isAsciiDigit((char) ('0' + i))); + } + + for (int i = 1; i <= 9; i++) { + assertFalse(isAsciiDigit((char) ('0' - i))); + } + + for (int i = 1; i <= 9; i++) { + assertFalse(isAsciiDigit((char) ('9' + i))); + } + } + @Test void testGetTopComponentType() { assertNull(getTopComponentType((Object) null)); @@ -724,14 +822,17 @@ void testIsAssignableFrom() { void testGetType() { assertNull(getType(null)); assertSame(String.class, getType("")); - assertSame(Class.class, getType(String.class)); + assertSame(String.class, getType(String.class)); + assertSame(Class.class, getType(Class.class)); + } @Test void testGetClass() { assertNull(ClassUtils.getClass(null)); assertSame(String.class, ClassUtils.getClass("")); - assertSame(Class.class, ClassUtils.getClass(String.class)); + assertSame(String.class, ClassUtils.getClass(String.class)); + assertSame(Class.class, ClassUtils.getClass(Class.class)); } @Test @@ -740,7 +841,7 @@ void testGetTypes() { assertSame(EMPTY_CLASS_ARRAY, getTypes()); assertSame(EMPTY_CLASS_ARRAY, getTypes(EMPTY_OBJECT_ARRAY)); - assertArrayEquals(ofArray(String.class, Integer.class), getTypes("", Integer.valueOf((1)))); + assertArrayEquals(ofArray(String.class, Integer.class), getTypes("", valueOf((1)))); } @Test @@ -749,7 +850,7 @@ void testGetClasses() { assertSame(EMPTY_CLASS_ARRAY, getClasses()); assertSame(EMPTY_CLASS_ARRAY, getClasses(EMPTY_OBJECT_ARRAY)); - assertArrayEquals(ofArray(String.class, Integer.class), getClasses("", Integer.valueOf((1)))); + assertArrayEquals(ofArray(String.class, Integer.class), getClasses("", valueOf((1)))); } @Test @@ -765,6 +866,7 @@ void testIsDerived() { @Test void testNewInstance() { assertEquals("test", newInstance(String.class, "test")); + assertEquals(valueOf(1), newInstance(Integer.class, valueOf(1))); assertThrows(IllegalArgumentException.class, () -> newInstance(String.class, 1)); } @@ -776,6 +878,27 @@ void testCast() { assertEquals("test", cast("test", CharSequence.class)); } + @Test + void testGetProtectionDomain() { + assertNull(getProtectionDomain(null)); + assertNotNull(getProtectionDomain(String.class)); + assertNotNull(getProtectionDomain(ClassUtilsTest.class)); + } + + @Test + void testGetCodeSource() { + assertNull(getCodeSource(null)); + assertNull(getCodeSource(String.class)); + assertNotNull(getCodeSource(ClassUtilsTest.class)); + } + + @Test + void testGetCodeSourceLocation() { + assertNull(getCodeSourceLocation(null)); + assertNull(getCodeSourceLocation(String.class)); + assertNotNull(getCodeSourceLocation(ClassUtilsTest.class)); + } + private void assertFindClassNamesMethod (Class targetClassInClassPath, BiFunction> findClassNamesFunction) { // Null @@ -793,5 +916,10 @@ void testCast() { assertFalse(findClassNamesFunction.apply(new File(path), true).isEmpty()); } + private void assertFindClassNamesInClassPath(URL location) { + String path = location.toString(); + Set classNamesInClassPath = findClassNamesInClassPath(path, true); + assertFalse(classNamesInClassPath.isEmpty()); + } } diff --git a/microsphere-java-core/src/test/java/io/microsphere/util/PriorityComparatorTest.java b/microsphere-java-core/src/test/java/io/microsphere/util/PriorityComparatorTest.java index bfedf9031..92835628b 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/util/PriorityComparatorTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/util/PriorityComparatorTest.java @@ -20,6 +20,7 @@ import javax.annotation.Priority; +import static io.microsphere.util.PriorityComparator.compare; import static org.junit.jupiter.api.Assertions.assertEquals; /** @@ -33,7 +34,7 @@ class PriorityComparatorTest { @Test - void test() { + void testCompileWithObject() { PriorityComparator comparator = PriorityComparator.INSTANCE; assertEquals(0, comparator.compare(new NoPriority(), new NoPriority())); assertEquals(0, comparator.compare(new PriorityOneType(), new PriorityOneType())); @@ -43,6 +44,16 @@ void test() { assertEquals(1, comparator.compare(new PriorityTwoType(), new PriorityOneType())); } + @Test + void testCompileWithSameTypes() { + assertEquals(0, compare(null, null, null)); + } + + @Test + void testCompileWithNullPriorityClass() { + assertEquals(0, compare(Object.class, String.class, null)); + } + static class NoPriority { } diff --git a/microsphere-java-core/src/test/java/io/microsphere/util/StopWatchTest.java b/microsphere-java-core/src/test/java/io/microsphere/util/StopWatchTest.java index ba110fd9c..2e0ec9f22 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/util/StopWatchTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/util/StopWatchTest.java @@ -17,12 +17,12 @@ package io.microsphere.util; import io.microsphere.logging.Logger; -import io.microsphere.logging.LoggerFactory; import io.microsphere.util.StopWatch.Task; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static io.microsphere.constants.SymbolConstants.SPACE; +import static io.microsphere.logging.LoggerFactory.getLogger; import static io.microsphere.util.StopWatch.Task.start; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -42,7 +42,7 @@ */ class StopWatchTest { - private static final Logger logger = LoggerFactory.getLogger(StopWatchTest.class); + private static final Logger logger = getLogger(StopWatchTest.class); private static final String testName = "test"; diff --git a/microsphere-java-core/src/test/java/io/microsphere/util/ThrowableUtilsTest.java b/microsphere-java-core/src/test/java/io/microsphere/util/ThrowableUtilsTest.java new file mode 100644 index 000000000..883f8e5e1 --- /dev/null +++ b/microsphere-java-core/src/test/java/io/microsphere/util/ThrowableUtilsTest.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.microsphere.util; + + +import io.microsphere.lang.function.ThrowableAction; +import org.junit.jupiter.api.Test; + +import static io.microsphere.lang.function.ThrowableAction.execute; +import static io.microsphere.util.ThrowableUtils.getRootCause; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * {@link ThrowableUtils} Test + * + * @author Mercy + * @see ThrowableUtils + * @since 1.0.0 + */ +class ThrowableUtilsTest { + + @Test + void testGetRootCause() { + Throwable rootCause = new Throwable("Root Cause"); + Throwable throwable = new Throwable("Throwable", rootCause); + assertSame(rootCause, getRootCause(throwable)); + + ThrowableAction action = () -> { + throw throwable; + }; + + execute(action, e -> { + assertSame(rootCause, getRootCause(e)); + }); + + assertThrows(NullPointerException.class, () -> { + try { + ThrowableAction a = () -> { + String s = null; + s.toString(); + }; + a.execute(); + } catch (Throwable e) { + throw getRootCause(e); + } + }); + } +} \ No newline at end of file diff --git a/microsphere-java-core/src/test/java/io/microsphere/util/jar/JarUtilsTest.java b/microsphere-java-core/src/test/java/io/microsphere/util/jar/JarUtilsTest.java index c398bfc82..33e11b93b 100644 --- a/microsphere-java-core/src/test/java/io/microsphere/util/jar/JarUtilsTest.java +++ b/microsphere-java-core/src/test/java/io/microsphere/util/jar/JarUtilsTest.java @@ -3,8 +3,8 @@ */ package io.microsphere.util.jar; +import io.microsphere.AbstractTestCase; import io.microsphere.filter.JarEntryFilter; -import io.microsphere.util.ClassLoaderUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -12,25 +12,34 @@ import java.io.File; import java.io.IOException; import java.net.URL; +import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; -import static io.microsphere.io.FileUtils.deleteDirectory; import static io.microsphere.net.URLUtils.ofURL; +import static io.microsphere.util.ClassLoaderUtils.ResourceType.PACKAGE; import static io.microsphere.util.ClassLoaderUtils.getClassLoader; import static io.microsphere.util.ClassLoaderUtils.getClassResource; -import static io.microsphere.util.SystemUtils.JAVA_IO_TMPDIR; +import static io.microsphere.util.ClassLoaderUtils.getResource; +import static io.microsphere.util.StringUtils.substringBeforeLast; import static io.microsphere.util.jar.JarUtils.MANIFEST_RESOURCE_PATH; import static io.microsphere.util.jar.JarUtils.assertJarURLProtocol; +import static io.microsphere.util.jar.JarUtils.doExtract; import static io.microsphere.util.jar.JarUtils.extract; +import static io.microsphere.util.jar.JarUtils.filter; import static io.microsphere.util.jar.JarUtils.findJarEntry; +import static io.microsphere.util.jar.JarUtils.isDirectoryEntry; import static io.microsphere.util.jar.JarUtils.resolveJarAbsolutePath; import static io.microsphere.util.jar.JarUtils.resolveRelativePath; import static io.microsphere.util.jar.JarUtils.toJarFile; +import static java.util.Collections.emptyList; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * {@link JarUtils} Test @@ -39,21 +48,18 @@ * @see JarUtilsTest * @since 1.0.0 */ -class JarUtilsTest { +class JarUtilsTest extends AbstractTestCase { - private final static File tempDirectory = new File(JAVA_IO_TMPDIR); - - private final static File targetDirectory = new File(tempDirectory, "jar-util-extract"); + private File targetDirectory; private final ClassLoader classLoader = getClassLoader(getClass()); private URL resourceURL; @BeforeEach - void setUp() throws IOException { - deleteDirectory(targetDirectory); - targetDirectory.mkdirs(); - this.resourceURL = getClassResource(classLoader, Nonnull.class); + void setUp() { + this.targetDirectory = createRandomTempDirectory(); + this.resourceURL = getClassResource(this.classLoader, Nonnull.class); } @Test @@ -63,57 +69,115 @@ void testConstants() { @Test void testAssertJarURLProtocol() { - URL url = ofURL("http://localhost"); - assertThrows(IllegalArgumentException.class, () -> assertJarURLProtocol(url)); + assertThrows(IllegalArgumentException.class, () -> assertJarURLProtocol(ofURL("http://localhost"))); + assertJarURLProtocol(ofURL("file://localhost")); } @Test void testResolveRelativePath() { - String relativePath = resolveRelativePath(resourceURL); + String relativePath = resolveRelativePath(this.resourceURL); String expectedPath = "javax/annotation/Nonnull.class"; assertEquals(expectedPath, relativePath); } @Test - void testResolveJarAbsolutePath() throws Exception { - String jarAbsolutePath = resolveJarAbsolutePath(resourceURL); + void testResolveJarAbsolutePath() { + String jarAbsolutePath = resolveJarAbsolutePath(this.resourceURL); assertNotNull(jarAbsolutePath); } @Test - void testToJarFile() throws Exception { - JarFile jarFile = toJarFile(resourceURL); + void testFilter() throws IOException { + JarFile jarFile = toJarFile(this.resourceURL); + List jarEntries = filter(jarFile, null); + assertFalse(jarEntries.isEmpty()); + } + + @Test + void testFilterOnNullJarFile() { + assertSame(emptyList(), filter(null, null)); + } + + @Test + void testToJarFile() throws IOException { + JarFile jarFile = toJarFile(this.resourceURL); assertNotNull(jarFile); } - public void testToJarFileOnException() throws Exception { - assertThrows(IllegalArgumentException.class, () -> { - URL url = new URL("http://www.google.com"); - JarFile jarFile = toJarFile(url); - }); + @Test + void testToJarFileOnNotFound() throws IOException { + URL url = new URL("jar:file:/path/to/file.jar!/entry"); + JarFile jarFile = toJarFile(url); + assertNull(jarFile); + } + + @Test + void testToJarFileOnInvalidProtocol() { + assertThrows(IllegalArgumentException.class, () -> toJarFile(new URL("http://github.com"))); + } + + @Test + void testToJarFileOnNPE() { + assertThrows(NullPointerException.class, () -> toJarFile(null)); } @Test void testFindJarEntry() throws Exception { - URL resourceURL = getClassResource(classLoader, Nonnull.class); + URL resourceURL = getClassResource(this.classLoader, Nonnull.class); JarEntry jarEntry = findJarEntry(resourceURL); assertNotNull(jarEntry); } @Test void testExtract() throws IOException { - String jarAbsolutePath = resolveJarAbsolutePath(resourceURL); - extract(new File(jarAbsolutePath), targetDirectory); + String jarAbsolutePath = resolveJarAbsolutePath(this.resourceURL); + extract(new File(jarAbsolutePath), this.targetDirectory); } @Test void testExtractWithURL() throws IOException { - URL resourceURL = ClassLoaderUtils.getResource(classLoader, ClassLoaderUtils.ResourceType.PACKAGE, "javax.annotation"); - extract(resourceURL, targetDirectory, new JarEntryFilter() { - @Override - public boolean accept(JarEntry filteredObject) { - return !filteredObject.isDirectory(); - } - }); + extract(this.resourceURL, this.targetDirectory, (JarEntryFilter) filteredObject -> !filteredObject.isDirectory()); + + URL resourceURL = getResource(this.classLoader, PACKAGE, "javax.annotation"); + extract(resourceURL, this.targetDirectory, (JarEntryFilter) filteredObject -> !filteredObject.isDirectory()); + } + + @Test + void testDoExtractOnNullJarFile() throws IOException { + doExtract(null, null, this.targetDirectory); + } + + @Test + void testDoExtractWithoutJarEntry() throws IOException { + JarFile jarFile = toJarFile(this.resourceURL); + doExtract(jarFile, null, this.targetDirectory); + } + + @Test + void testDoExtractOnMissingMatch() throws IOException { + URL resourceURL = getClassResource(this.classLoader, Test.class); + JarFile jarFile = toJarFile(resourceURL); + List jarEntries = filter(jarFile, null); + doExtract(toJarFile(this.resourceURL), jarEntries, this.targetDirectory); + } + + @Test + void testIsDirectoryEntry() throws IOException { + File tempFile = createRandomTempFile(); + resourceURL = tempFile.toURI().toURL(); + assertFalse(isDirectoryEntry(resourceURL)); + + URL resourceURL = getResource(this.classLoader, PACKAGE, "javax.annotation"); + assertTrue(isDirectoryEntry(resourceURL)); + + String path = substringBeforeLast(resourceURL.toString(), "javax/annotation"); + resourceURL = ofURL(path); + assertTrue(isDirectoryEntry(resourceURL)); + + resourceURL = getClassResource(this.classLoader, Nonnull.class); + assertFalse(isDirectoryEntry(resourceURL)); + + resourceURL = ofURL("jar:file:/path/to/file.jar!/com/acme/"); + assertFalse(isDirectoryEntry(resourceURL)); } } diff --git a/microsphere-java-core/src/test/resources/META-INF/empty-class-name.sar b/microsphere-java-core/src/test/resources/META-INF/empty-class-name.sar new file mode 100644 index 000000000..42299b6d4 Binary files /dev/null and b/microsphere-java-core/src/test/resources/META-INF/empty-class-name.sar differ diff --git a/microsphere-java-core/src/test/resources/META-INF/empty.sar b/microsphere-java-core/src/test/resources/META-INF/empty.sar new file mode 100644 index 000000000..55d3c3e3c Binary files /dev/null and b/microsphere-java-core/src/test/resources/META-INF/empty.sar differ diff --git a/microsphere-java-core/src/test/resources/META-INF/services/io.microsphere.logging.LoggerFactory b/microsphere-java-core/src/test/resources/META-INF/services/io.microsphere.logging.LoggerFactory new file mode 100644 index 000000000..3c3e4d472 --- /dev/null +++ b/microsphere-java-core/src/test/resources/META-INF/services/io.microsphere.logging.LoggerFactory @@ -0,0 +1 @@ +io.microsphere.logging.NoDelegateLoggerFactory \ No newline at end of file diff --git a/microsphere-java-core/src/test/resources/junit-platform.properties b/microsphere-java-core/src/test/resources/junit-platform.properties index 1cebb76d5..5c558927b 100644 --- a/microsphere-java-core/src/test/resources/junit-platform.properties +++ b/microsphere-java-core/src/test/resources/junit-platform.properties @@ -1 +1,3 @@ -junit.jupiter.extensions.autodetection.enabled = true \ No newline at end of file +junit.jupiter.extensions.autodetection.enabled = true + +junit.jupiter.execution.parallel.enabled = false \ No newline at end of file diff --git a/microsphere-java-dependencies/pom.xml b/microsphere-java-dependencies/pom.xml index 1f36e1c37..aba268cdb 100644 --- a/microsphere-java-dependencies/pom.xml +++ b/microsphere-java-dependencies/pom.xml @@ -23,7 +23,7 @@ io.github.microsphere-projects - microsphere-annotation-processor + microsphere-java-annotations ${revision} @@ -33,6 +33,30 @@ ${revision} + + io.github.microsphere-projects + microsphere-jdk-tools + ${revision} + + + + io.github.microsphere-projects + microsphere-java-test + ${revision} + + + + io.github.microsphere-projects + microsphere-lang-model + ${revision} + + + + io.github.microsphere-projects + microsphere-annotation-processor + ${revision} + + diff --git a/microsphere-java-parent/pom.xml b/microsphere-java-parent/pom.xml index 5e554cb8b..8080f4b93 100644 --- a/microsphere-java-parent/pom.xml +++ b/microsphere-java-parent/pom.xml @@ -20,6 +20,8 @@ 1.3.2 + 2.1 + 2.3.1 3.0.2 1.3.2 7.0.3 @@ -27,10 +29,10 @@ 1.5.26 6.0.2 + 5.14.2 1.37 - @@ -42,6 +44,22 @@ ${javax.annotation-api.version} + + + javax.ws.rs + javax.ws.rs-api + ${javax.ws.rs.version} + true + + + + + javax.xml.ws + jaxws-api + ${jaxws-api.version} + true + + com.google.code.findbugs @@ -82,6 +100,14 @@ ${junit.version} + + + org.mockito + mockito-core + ${mockito.version} + + + org.openjdk.jmh jmh-core @@ -126,7 +152,8 @@ 5.3.39 - 5.13.4 + 5.14.2 + 4.11.0 diff --git a/microsphere-java-test/pom.xml b/microsphere-java-test/pom.xml new file mode 100644 index 000000000..40504c98e --- /dev/null +++ b/microsphere-java-test/pom.xml @@ -0,0 +1,94 @@ + + + + io.github.microsphere-projects + microsphere-java-parent + ${revision} + ../microsphere-java-parent/pom.xml + + 4.0.0 + + io.github.microsphere-projects + microsphere-java-test + ${revision} + jar + + Microsphere :: Java :: Test + Microsphere Java Test + + + + + + io.github.microsphere-projects + microsphere-java-core + ${revision} + + + + + io.github.microsphere-projects + microsphere-jdk-tools + ${revision} + true + + + + + org.junit.jupiter + junit-jupiter + true + + + + + org.mockito + mockito-core + true + + + + org.junit.jupiter + junit-jupiter-engine + true + + + + + ch.qos.logback + logback-classic + true + + + + + javax.ws.rs + javax.ws.rs-api + true + + + + + javax.xml.ws + jaxws-api + true + + + + + org.springframework + spring-context + true + + + + org.springframework + spring-web + true + + + + + \ No newline at end of file diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/TestAnnotation.java b/microsphere-java-test/src/main/java/io/microsphere/test/annotation/TestAnnotation.java similarity index 97% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/TestAnnotation.java rename to microsphere-java-test/src/main/java/io/microsphere/test/annotation/TestAnnotation.java index 4d35d6f82..5669e4936 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/TestAnnotation.java +++ b/microsphere-java-test/src/main/java/io/microsphere/test/annotation/TestAnnotation.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package io.microsphere.annotation.processor; +package io.microsphere.test.annotation; import io.microsphere.annotation.ConfigurationProperty; import io.microsphere.annotation.Since; @@ -70,4 +70,4 @@ ConfigurationProperty[] properties() default {}; -} +} \ No newline at end of file diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/AbstractAnnotationProcessingTest.java b/microsphere-java-test/src/main/java/io/microsphere/test/annotation/processing/AbstractAnnotationProcessingTest.java similarity index 61% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/AbstractAnnotationProcessingTest.java rename to microsphere-java-test/src/main/java/io/microsphere/test/annotation/processing/AbstractAnnotationProcessingTest.java index ce674e512..57f4a8daf 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/AbstractAnnotationProcessingTest.java +++ b/microsphere-java-test/src/main/java/io/microsphere/test/annotation/processing/AbstractAnnotationProcessingTest.java @@ -14,12 +14,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor; +package io.microsphere.test.annotation.processing; -import io.microsphere.annotation.processor.util.TypeUtils; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; +import io.microsphere.annotation.Nullable; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ReflectiveInvocationContext; import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; @@ -36,19 +36,13 @@ import javax.lang.model.util.Elements; import javax.lang.model.util.Types; import java.lang.annotation.Annotation; +import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.Collection; import java.util.List; import java.util.Set; import java.util.function.Predicate; -import static io.microsphere.annotation.processor.util.ConstructorUtils.findConstructor; -import static io.microsphere.annotation.processor.util.FieldUtils.findField; -import static io.microsphere.annotation.processor.util.MethodUtils.findMethod; -import static io.microsphere.annotation.processor.util.TypeUtils.ofDeclaredType; -import static java.util.Collections.emptyList; -import static org.junit.jupiter.api.Assertions.assertSame; - /** * Abstract {@link Annotation} Processing Test case * @@ -112,8 +106,6 @@ public abstract class AbstractAnnotationProcessingTest { protected static final AnnotationMirror NULL_ANNOTATION_MIRROR = null; - static ThreadLocal testInstanceHolder = new ThreadLocal<>(); - protected RoundEnvironment roundEnv; protected ProcessingEnvironment processingEnv; @@ -132,71 +124,40 @@ public abstract class AbstractAnnotationProcessingTest { protected DeclaredType testDeclaredType; - @BeforeEach - final void setUp() { - testInstanceHolder.set(this); - } - - @AfterEach - final void tearDown() { - testInstanceHolder.remove(); - } - + /** + * The classes to be compiled. + * + * @param compiledClasses the mutable {@link Set} for classes to be compiled + */ protected void addCompiledClasses(Set> compiledClasses) { } - protected void beforeTest() { - this.testClass = TestServiceImpl.class; - this.testClassName = TestServiceImpl.class.getName(); - this.testTypeElement = getTypeElement(testClass); + protected void initTestClass(Class testClass) { + this.testClass = testClass; + this.testClassName = testClass.getName(); + this.testTypeElement = this.elements.getTypeElement(this.testClassName); this.testTypeMirror = this.testTypeElement.asType(); - this.testDeclaredType = ofDeclaredType(this.testTypeElement); + this.testDeclaredType = (DeclaredType) this.testTypeMirror; } - protected void afterTest() { + /** + * Before Test + * + * @param invocationContext {@link ReflectiveInvocationContext} + * @param extensionContext {@link ExtensionContext} + */ + protected void beforeTest(ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) { } - protected List getTypeMirrors(Type... types) { - return TypeUtils.getTypeMirrors(processingEnv, types); + /** + * After Test + * + * @param invocationContext {@link ReflectiveInvocationContext} + * @param extensionContext {@link ExtensionContext} + * @param result the result after test method returning + * @param failure the failure after the test methods' execution + */ + protected void afterTest(ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext, + @Nullable Object result, @Nullable Throwable failure) { } - - protected TypeMirror getTypeMirror(Type type) { - return TypeUtils.getTypeMirror(processingEnv, type); - } - - protected List getTypeElements(Type... types) { - return TypeUtils.getTypeElements(processingEnv, types); - } - - protected TypeElement getTypeElement(Type type) { - return TypeUtils.getTypeElement(processingEnv, type); - } - - protected VariableElement getField(Type type, String fieldName) { - TypeElement typeElement = getTypeElement(type); - return findField(typeElement, fieldName); - } - - protected ExecutableElement getMethod(Type type, String methodName, Type... parameterTypes) { - TypeElement typeElement = getTypeElement(type); - return findMethod(typeElement, methodName, parameterTypes); - } - - protected ExecutableElement getConstructor(Type type, Type... parameterTypes) { - TypeElement typeElement = getTypeElement(type); - return findConstructor(typeElement, parameterTypes); - } - - protected Element[] getElements(Type... types) { - return getTypeMirrors(types).stream().map(TypeUtils::ofTypeElement).toArray(Element[]::new); - } - - protected DeclaredType getDeclaredType(Type type) { - return TypeUtils.getDeclaredType(processingEnv, type); - } - - protected void assertEmptyList(List list) { - assertSame(emptyList(), list); - } - -} +} \ No newline at end of file diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/AnnotationProcessingTestProcessor.java b/microsphere-java-test/src/main/java/io/microsphere/test/annotation/processing/AnnotationProcessingTestProcessor.java similarity index 55% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/AnnotationProcessingTestProcessor.java rename to microsphere-java-test/src/main/java/io/microsphere/test/annotation/processing/AnnotationProcessingTestProcessor.java index 68e28ccd0..3192d0140 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/AnnotationProcessingTestProcessor.java +++ b/microsphere-java-test/src/main/java/io/microsphere/test/annotation/processing/AnnotationProcessingTestProcessor.java @@ -14,21 +14,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor; +package io.microsphere.test.annotation.processing; import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.api.extension.InvocationInterceptor; +import org.junit.jupiter.api.extension.InvocationInterceptor.Invocation; import org.junit.jupiter.api.extension.ReflectiveInvocationContext; import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.lang.model.SourceVersion; import javax.lang.model.element.TypeElement; +import javax.lang.model.util.Elements; +import javax.lang.model.util.Types; import java.lang.reflect.Method; import java.util.Set; import static io.microsphere.constants.SymbolConstants.WILDCARD; +import static io.microsphere.util.ExceptionUtils.wrap; +import static io.microsphere.util.ThrowableUtils.getRootCause; import static javax.lang.model.SourceVersion.latestSupported; /** @@ -38,18 +43,19 @@ * @since 1.0.0 */ @SupportedAnnotationTypes(WILDCARD) -public class AnnotationProcessingTestProcessor extends AbstractProcessor { +class AnnotationProcessingTestProcessor extends AbstractProcessor { private final AbstractAnnotationProcessingTest abstractAnnotationProcessingTest; - private final InvocationInterceptor.Invocation invocation; + + private final Invocation invocation; private final ReflectiveInvocationContext invocationContext; private final ExtensionContext extensionContext; - public AnnotationProcessingTestProcessor(AbstractAnnotationProcessingTest abstractAnnotationProcessingTest, InvocationInterceptor.Invocation invocation, - ReflectiveInvocationContext invocationContext, - ExtensionContext extensionContext) { + AnnotationProcessingTestProcessor(AbstractAnnotationProcessingTest abstractAnnotationProcessingTest, Invocation invocation, + ReflectiveInvocationContext invocationContext, + ExtensionContext extensionContext) { this.abstractAnnotationProcessingTest = abstractAnnotationProcessingTest; this.invocation = invocation; this.invocationContext = invocationContext; @@ -58,25 +64,39 @@ public AnnotationProcessingTestProcessor(AbstractAnnotationProcessingTest abstra @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { + ReflectiveInvocationContext invocationContext = this.invocationContext; + ExtensionContext extensionContext = this.extensionContext; if (!roundEnv.processingOver()) { prepare(roundEnv); - abstractAnnotationProcessingTest.beforeTest(); + Object result = null; + Throwable failure = null; + abstractAnnotationProcessingTest.beforeTest(invocationContext, extensionContext); try { - invocation.proceed(); + result = invocation.proceed(); } catch (Throwable throwable) { - throw new RuntimeException(throwable); + failure = throwable; } finally { - abstractAnnotationProcessingTest.afterTest(); + abstractAnnotationProcessingTest.afterTest(invocationContext, extensionContext, result, failure); + } + if (failure != null) { + Throwable cause = getRootCause(failure); + throw wrap(cause, Error.class); } } return false; } - protected void prepare(RoundEnvironment roundEnv) { + void prepare(RoundEnvironment roundEnv) { + ProcessingEnvironment processingEnv = super.processingEnv; + Elements elements = processingEnv.getElementUtils(); + Types types = processingEnv.getTypeUtils(); + Class testClass = this.invocationContext.getTargetClass(); + abstractAnnotationProcessingTest.roundEnv = roundEnv; - abstractAnnotationProcessingTest.processingEnv = super.processingEnv; - abstractAnnotationProcessingTest.elements = super.processingEnv.getElementUtils(); - abstractAnnotationProcessingTest.types = super.processingEnv.getTypeUtils(); + abstractAnnotationProcessingTest.processingEnv = processingEnv; + abstractAnnotationProcessingTest.elements = elements; + abstractAnnotationProcessingTest.types = types; + abstractAnnotationProcessingTest.initTestClass(testClass); } @Override diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/CompilerInvocationInterceptor.java b/microsphere-java-test/src/main/java/io/microsphere/test/annotation/processing/CompilerInvocationInterceptor.java similarity index 56% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/CompilerInvocationInterceptor.java rename to microsphere-java-test/src/main/java/io/microsphere/test/annotation/processing/CompilerInvocationInterceptor.java index 966e6defa..c45776142 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/CompilerInvocationInterceptor.java +++ b/microsphere-java-test/src/main/java/io/microsphere/test/annotation/processing/CompilerInvocationInterceptor.java @@ -14,8 +14,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor; +package io.microsphere.test.annotation.processing; +import io.microsphere.jdk.tools.compiler.Compiler; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.InvocationInterceptor; import org.junit.jupiter.api.extension.ReflectiveInvocationContext; @@ -25,10 +26,11 @@ import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; +import java.util.ServiceLoader; import java.util.Set; -import static io.microsphere.annotation.processor.AbstractAnnotationProcessingTest.testInstanceHolder; -import static io.microsphere.util.ServiceLoaderUtils.loadServicesList; +import static io.microsphere.util.ArrayUtils.EMPTY_CLASS_ARRAY; +import static java.util.ServiceLoader.load; /** @@ -37,21 +39,29 @@ * @author Mercy * @since 1.0.0 */ -public class CompilerInvocationInterceptor implements InvocationInterceptor { +class CompilerInvocationInterceptor implements InvocationInterceptor { @Override - public void interceptTestMethod(Invocation invocation, - ReflectiveInvocationContext invocationContext, + public void interceptTestMethod(Invocation invocation, ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) throws Throwable { - Set> compiledClasses = new LinkedHashSet<>(); - AbstractAnnotationProcessingTest abstractAnnotationProcessingTest = testInstanceHolder.get(); - compiledClasses.add(getClass()); - abstractAnnotationProcessingTest.addCompiledClasses(compiledClasses); + Set> compiledClassesSet = new LinkedHashSet<>(); + AbstractAnnotationProcessingTest test = (AbstractAnnotationProcessingTest) invocationContext.getTarget().get(); + Class testClass = extensionContext.getTestClass().get(); + ClassLoader classLoader = testClass.getClassLoader(); + compiledClassesSet.add(testClass); + test.addCompiledClasses(compiledClassesSet); + + Class[] compiledClasses = compiledClassesSet.toArray(EMPTY_CLASS_ARRAY); + Compiler compiler = new Compiler(); compiler.sourcePaths(compiledClasses); - List processors = new LinkedList<>(loadServicesList(Processor.class, this.getClass().getClassLoader())); - processors.add(new AnnotationProcessingTestProcessor(abstractAnnotationProcessingTest, invocation, invocationContext, extensionContext)); + + List processors = new LinkedList<>(); + processors.add(new AnnotationProcessingTestProcessor(test, invocation, invocationContext, extensionContext)); + // Loads the SPI instances of Processor + ServiceLoader loadedProcessors = load(Processor.class, classLoader); + loadedProcessors.forEach(processors::add); compiler.processors(processors.toArray(new Processor[0])); - compiler.compile(compiledClasses.toArray(new Class[0])); + compiler.compile(compiledClasses); } -} +} \ No newline at end of file diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/Ancestor.java b/microsphere-java-test/src/main/java/io/microsphere/test/model/Ancestor.java similarity index 90% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/Ancestor.java rename to microsphere-java-test/src/main/java/io/microsphere/test/model/Ancestor.java index 9a749d056..cf0e07f70 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/Ancestor.java +++ b/microsphere-java-test/src/main/java/io/microsphere/test/model/Ancestor.java @@ -14,12 +14,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor.model; +package io.microsphere.test.model; import java.io.Serializable; /** * Ancestor + * + * @author Mercy + * @since 1.0.0 */ public class Ancestor implements Serializable { @@ -32,4 +35,4 @@ public boolean isZ() { public void setZ(boolean z) { this.z = z; } -} +} \ No newline at end of file diff --git a/microsphere-java-test/src/main/java/io/microsphere/test/model/ArrayTypeModel.java b/microsphere-java-test/src/main/java/io/microsphere/test/model/ArrayTypeModel.java new file mode 100644 index 000000000..d9588781e --- /dev/null +++ b/microsphere-java-test/src/main/java/io/microsphere/test/model/ArrayTypeModel.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.microsphere.test.model; + +/** + * Array Type Model + * + * @author Mercy + * @since 1.0.0 + */ +public class ArrayTypeModel { + + private int[] integers; // Primitive type array + + private String[] strings; // Simple type array + + private PrimitiveTypeModel[] primitiveTypeModels; // Complex type array + + private Model[] models; // Hierarchical Complex type array + + private Color[] colors; // Enum type array + + public int[] getIntegers() { + return integers; + } + + public void setIntegers(int[] integers) { + this.integers = integers; + } + + public String[] getStrings() { + return strings; + } + + public void setStrings(String[] strings) { + this.strings = strings; + } + + public PrimitiveTypeModel[] getPrimitiveTypeModels() { + return primitiveTypeModels; + } + + public void setPrimitiveTypeModels(PrimitiveTypeModel[] primitiveTypeModels) { + this.primitiveTypeModels = primitiveTypeModels; + } + + public Model[] getModels() { + return models; + } + + public void setModels(Model[] models) { + this.models = models; + } + + public Color[] getColors() { + return colors; + } + + public void setColors(Color[] colors) { + this.colors = colors; + } +} \ No newline at end of file diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/CollectionTypeModel.java b/microsphere-java-test/src/main/java/io/microsphere/test/model/CollectionTypeModel.java similarity index 58% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/CollectionTypeModel.java rename to microsphere-java-test/src/main/java/io/microsphere/test/model/CollectionTypeModel.java index 3f5426361..414d65451 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/CollectionTypeModel.java +++ b/microsphere-java-test/src/main/java/io/microsphere/test/model/CollectionTypeModel.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor.model; +package io.microsphere.test.model; import java.util.Collection; import java.util.Deque; @@ -25,6 +25,7 @@ /** * {@link Collection} Type Model * + * @author Mercy * @since 1.0.0 */ public class CollectionTypeModel { @@ -39,4 +40,43 @@ public class CollectionTypeModel { private Set modelArrays; // The composite element is hierarchical POJO type -} + public Collection getStrings() { + return strings; + } + + public void setStrings(Collection strings) { + this.strings = strings; + } + + public List getColors() { + return colors; + } + + public void setColors(List colors) { + this.colors = colors; + } + + public Queue getPrimitiveTypeModels() { + return primitiveTypeModels; + } + + public void setPrimitiveTypeModels(Queue primitiveTypeModels) { + this.primitiveTypeModels = primitiveTypeModels; + } + + public Deque getModels() { + return models; + } + + public void setModels(Deque models) { + this.models = models; + } + + public Set getModelArrays() { + return modelArrays; + } + + public void setModelArrays(Set modelArrays) { + this.modelArrays = modelArrays; + } +} \ No newline at end of file diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/Color.java b/microsphere-java-test/src/main/java/io/microsphere/test/model/Color.java similarity index 92% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/Color.java rename to microsphere-java-test/src/main/java/io/microsphere/test/model/Color.java index 177dfaffc..f362a8376 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/Color.java +++ b/microsphere-java-test/src/main/java/io/microsphere/test/model/Color.java @@ -14,11 +14,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor.model; +package io.microsphere.test.model; /** * Color enumeration * + * @author Mercy * @since 1.0.0 */ public enum Color { @@ -43,4 +44,4 @@ public String toString() { public int getValue() { return value; } -} +} \ No newline at end of file diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/ConfigurationPropertyModel.java b/microsphere-java-test/src/main/java/io/microsphere/test/model/ConfigurationPropertyModel.java similarity index 67% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/ConfigurationPropertyModel.java rename to microsphere-java-test/src/main/java/io/microsphere/test/model/ConfigurationPropertyModel.java index 9a6505460..a8e206bd0 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/ConfigurationPropertyModel.java +++ b/microsphere-java-test/src/main/java/io/microsphere/test/model/ConfigurationPropertyModel.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package io.microsphere.annotation.processor.model; +package io.microsphere.test.model; import io.microsphere.annotation.ConfigurationProperty; @@ -43,5 +43,43 @@ public class ConfigurationPropertyModel { @ConfigurationProperty(name = "microsphere.annotation.processor.model.description") private String description; + public String getName() { + return name; + } -} + public void setName(String name) { + this.name = name; + } + + public Class getType() { + return type; + } + + public void setType(Class type) { + this.type = type; + } + + public String getDefaultValue() { + return defaultValue; + } + + public void setDefaultValue(String defaultValue) { + this.defaultValue = defaultValue; + } + + public boolean isRequired() { + return required; + } + + public void setRequired(boolean required) { + this.required = required; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } +} \ No newline at end of file diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/MapTypeModel.java b/microsphere-java-test/src/main/java/io/microsphere/test/model/MapTypeModel.java similarity index 57% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/MapTypeModel.java rename to microsphere-java-test/src/main/java/io/microsphere/test/model/MapTypeModel.java index 3c9fc58c4..bf051c5b9 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/MapTypeModel.java +++ b/microsphere-java-test/src/main/java/io/microsphere/test/model/MapTypeModel.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor.model; +package io.microsphere.test.model; import java.util.HashMap; import java.util.Map; @@ -25,6 +25,7 @@ /** * {@link Map} Type model * + * @author Mercy * @since 1.0.0 */ public class MapTypeModel { @@ -38,4 +39,44 @@ public class MapTypeModel { private HashMap models; // The composite element is hierarchical POJO type private TreeMap modelArrays; // The composite element is hierarchical POJO type -} + + public Map getStrings() { + return strings; + } + + public void setStrings(Map strings) { + this.strings = strings; + } + + public SortedMap getColors() { + return colors; + } + + public void setColors(SortedMap colors) { + this.colors = colors; + } + + public NavigableMap getPrimitiveTypeModels() { + return primitiveTypeModels; + } + + public void setPrimitiveTypeModels(NavigableMap primitiveTypeModels) { + this.primitiveTypeModels = primitiveTypeModels; + } + + public HashMap getModels() { + return models; + } + + public void setModels(HashMap models) { + this.models = models; + } + + public TreeMap getModelArrays() { + return modelArrays; + } + + public void setModelArrays(TreeMap modelArrays) { + this.modelArrays = modelArrays; + } +} \ No newline at end of file diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/Model.java b/microsphere-java-test/src/main/java/io/microsphere/test/model/Model.java similarity index 94% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/Model.java rename to microsphere-java-test/src/main/java/io/microsphere/test/model/Model.java index 08348e513..5d972f3c9 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/Model.java +++ b/microsphere-java-test/src/main/java/io/microsphere/test/model/Model.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor.model; +package io.microsphere.test.model; import java.math.BigDecimal; import java.math.BigInteger; @@ -22,6 +22,9 @@ /** * Model Object + * + * @author Mercy + * @since 1.0.0 */ public class Model extends Parent { @@ -84,4 +87,4 @@ public BigDecimal getBd() { public void setBd(BigDecimal bd) { this.bd = bd; } -} +} \ No newline at end of file diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/Parent.java b/microsphere-java-test/src/main/java/io/microsphere/test/model/Parent.java similarity index 92% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/Parent.java rename to microsphere-java-test/src/main/java/io/microsphere/test/model/Parent.java index b124fb814..f5e85fe1e 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/Parent.java +++ b/microsphere-java-test/src/main/java/io/microsphere/test/model/Parent.java @@ -14,10 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor.model; +package io.microsphere.test.model; /** * Parent + * + * @author Mercy + * @since 1.0.0 */ public class Parent extends Ancestor { @@ -60,4 +63,4 @@ public long getL() { public void setL(long l) { this.l = l; } -} +} \ No newline at end of file diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/PrimitiveTypeModel.java b/microsphere-java-test/src/main/java/io/microsphere/test/model/PrimitiveTypeModel.java similarity index 93% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/PrimitiveTypeModel.java rename to microsphere-java-test/src/main/java/io/microsphere/test/model/PrimitiveTypeModel.java index 2bbe5372b..5a1065fc7 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/PrimitiveTypeModel.java +++ b/microsphere-java-test/src/main/java/io/microsphere/test/model/PrimitiveTypeModel.java @@ -14,11 +14,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor.model; +package io.microsphere.test.model; /** * Primitive Type model * + * @author Mercy * @since 1.0.0 */ public class PrimitiveTypeModel { @@ -70,4 +71,4 @@ public float getF() { public double getD() { return d; } -} +} \ No newline at end of file diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/SimpleTypeModel.java b/microsphere-java-test/src/main/java/io/microsphere/test/model/SimpleTypeModel.java similarity index 96% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/SimpleTypeModel.java rename to microsphere-java-test/src/main/java/io/microsphere/test/model/SimpleTypeModel.java index 4522d5554..86a8b6b8b 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/SimpleTypeModel.java +++ b/microsphere-java-test/src/main/java/io/microsphere/test/model/SimpleTypeModel.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor.model; +package io.microsphere.test.model; import java.math.BigDecimal; import java.math.BigInteger; @@ -23,6 +23,7 @@ /** * Simple Type model * + * @author Mercy * @since 1.0.0 */ public class SimpleTypeModel { @@ -158,4 +159,4 @@ public Date getDt() { public void setDt(Date dt) { this.dt = dt; } -} +} \ No newline at end of file diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/StringArrayList.java b/microsphere-java-test/src/main/java/io/microsphere/test/model/StringArrayList.java similarity index 95% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/StringArrayList.java rename to microsphere-java-test/src/main/java/io/microsphere/test/model/StringArrayList.java index f59710d58..e7c115a09 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/StringArrayList.java +++ b/microsphere-java-test/src/main/java/io/microsphere/test/model/StringArrayList.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package io.microsphere.annotation.processor.model; +package io.microsphere.test.model; import java.util.ArrayList; @@ -27,4 +27,4 @@ * @since 1.0.0 */ public class StringArrayList extends ArrayList { -} +} \ No newline at end of file diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/DefaultTestService.java b/microsphere-java-test/src/main/java/io/microsphere/test/service/DefaultTestService.java similarity index 93% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/DefaultTestService.java rename to microsphere-java-test/src/main/java/io/microsphere/test/service/DefaultTestService.java index 7e643daab..4ca1d694b 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/DefaultTestService.java +++ b/microsphere-java-test/src/main/java/io/microsphere/test/service/DefaultTestService.java @@ -14,10 +14,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor; +package io.microsphere.test.service; -import io.microsphere.annotation.processor.model.Model; +import io.microsphere.test.model.Model; import java.util.concurrent.TimeUnit; diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/GenericTestService.java b/microsphere-java-test/src/main/java/io/microsphere/test/service/GenericTestService.java similarity index 96% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/GenericTestService.java rename to microsphere-java-test/src/main/java/io/microsphere/test/service/GenericTestService.java index 449b73611..d4a81a787 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/GenericTestService.java +++ b/microsphere-java-test/src/main/java/io/microsphere/test/service/GenericTestService.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor; +package io.microsphere.test.service; import java.util.EventListener; @@ -30,4 +30,4 @@ public class GenericTestService extends DefaultTestService implements TestServic public String echo(String message) { return "[ECHO] " + message; } -} +} \ No newline at end of file diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/TestService.java b/microsphere-java-test/src/main/java/io/microsphere/test/service/TestService.java similarity index 93% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/TestService.java rename to microsphere-java-test/src/main/java/io/microsphere/test/service/TestService.java index 860748c13..22839bc80 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/TestService.java +++ b/microsphere-java-test/src/main/java/io/microsphere/test/service/TestService.java @@ -14,9 +14,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor; +package io.microsphere.test.service; -import io.microsphere.annotation.processor.model.Model; + +import io.microsphere.test.model.Model; import javax.ws.rs.DefaultValue; import javax.ws.rs.GET; diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/TestServiceImpl.java b/microsphere-java-test/src/main/java/io/microsphere/test/service/TestServiceImpl.java similarity index 95% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/TestServiceImpl.java rename to microsphere-java-test/src/main/java/io/microsphere/test/service/TestServiceImpl.java index e587e888e..27a53b2d3 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/TestServiceImpl.java +++ b/microsphere-java-test/src/main/java/io/microsphere/test/service/TestServiceImpl.java @@ -14,10 +14,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor; +package io.microsphere.test.service; import io.microsphere.annotation.ConfigurationProperty; import io.microsphere.annotation.Since; +import io.microsphere.test.annotation.TestAnnotation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.Cacheable; import org.springframework.context.ApplicationContext; @@ -76,9 +77,9 @@ public class TestServiceImpl extends GenericTestService implements TestService, AutoCloseable, Serializable { @Autowired - private ApplicationContext context; + protected ApplicationContext context; - private Environment environment; + protected Environment environment; public TestServiceImpl() { this(null); diff --git a/microsphere-java-test/src/main/resources/junit-platform.properties b/microsphere-java-test/src/main/resources/junit-platform.properties new file mode 100644 index 000000000..1e4594242 --- /dev/null +++ b/microsphere-java-test/src/main/resources/junit-platform.properties @@ -0,0 +1,5 @@ +junit.jupiter.extensions.autodetection.enabled = true + +junit.jupiter.execution.parallel.enabled = true +junit.jupiter.execution.parallel.mode.default = concurrent +junit.jupiter.execution.parallel.mode.classes.default = concurrent \ No newline at end of file diff --git a/microsphere-java-test/src/main/resources/logback-test.xml b/microsphere-java-test/src/main/resources/logback-test.xml new file mode 100644 index 000000000..e3375b74c --- /dev/null +++ b/microsphere-java-test/src/main/resources/logback-test.xml @@ -0,0 +1,15 @@ + + + + + + + ${ENCODER_PATTERN} + + + + + + + + \ No newline at end of file diff --git a/microsphere-java-test/src/test/java/io/microsphere/test/annotation/processing/AnnotationProcessingTest.java b/microsphere-java-test/src/test/java/io/microsphere/test/annotation/processing/AnnotationProcessingTest.java new file mode 100644 index 000000000..9b40f9b77 --- /dev/null +++ b/microsphere-java-test/src/test/java/io/microsphere/test/annotation/processing/AnnotationProcessingTest.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.microsphere.test.annotation.processing; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ReflectiveInvocationContext; +import org.junit.jupiter.api.extension.TestExecutionExceptionHandler; + +import javax.lang.model.element.Element; +import javax.lang.model.type.TypeMirror; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.Collection; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +/** + * {@link AbstractAnnotationProcessingTest} Test + * + * @author Mercy + * @see AbstractAnnotationProcessingTest + * @since 1.0.0 + */ +public class AnnotationProcessingTest extends AbstractAnnotationProcessingTest implements TestExecutionExceptionHandler { + + @Test + void test() { + assertNull(NULL_TYPE_MIRROR); + assertArrayEquals(new TypeMirror[0], EMPTY_TYPE_MIRROR_ARRAY); + assertNull(NULL_TYPE_MIRROR_ARRAY); + assertArrayEquals(new Collection[0], EMPTY_COLLECTION_ARRAY); + assertNull(NULL_COLLECTION); + assertNull(NULL_LIST); + assertNull(NULL_ELEMENT); + assertNull(NULL_ELEMENT_KIND); + assertArrayEquals(new Element[0], EMPTY_ELEMENT_ARRAY); + assertNull(NULL_ELEMENT_ARRAY); + assertNull(NULL_TYPE_ELEMENT); + assertNull(NULL_TYPE_ARRAY); + assertArrayEquals(new Type[0], EMPTY_TYPE_ARRAY); + assertNull(NULL_TYPE); + assertNull(NULL_PROCESSING_ENVIRONMENT); + assertNull(NULL_STRING); + assertNull(NULL_STRING_ARRAY); + assertNull(NULL_CLASS); + assertNull(NULL_CLASS_ARRAY); + assertNull(NULL_ANNOTATED_CONSTRUCT); + assertNull(NULL_PREDICATE_ARRAY); + assertNull(NULL_FIELD); + assertNull(NULL_MODIFIER); + assertNull(NULL_MODIFIER_ARRAY); + assertNull(NULL_METHOD); + assertNull(NULL_METHOD_ARRAY); + assertNull(NULL_ANNOTATION_MIRROR); + } + + @Test + @ExtendWith(AnnotationProcessingTest.class) + void testOnFailure() { + throw new RuntimeException("For testing"); + } + + @Override + protected void afterTest(ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext, Object result, Throwable failure) { + super.afterTest(invocationContext, extensionContext, result, failure); + if (failure != null) { + assertEquals("For testing", failure.getMessage()); + } + } + + @Override + public void handleTestExecutionException(ExtensionContext context, Throwable throwable) throws Throwable { + if (throwable != null) { + Method method = context.getTestMethod().get(); + if ("testOnFailure".equals(method.getName())) { + // ingnore + } + } + } +} \ No newline at end of file diff --git a/microsphere-java-test/src/test/java/io/microsphere/test/model/AncestorTest.java b/microsphere-java-test/src/test/java/io/microsphere/test/model/AncestorTest.java new file mode 100644 index 000000000..b96c57b36 --- /dev/null +++ b/microsphere-java-test/src/test/java/io/microsphere/test/model/AncestorTest.java @@ -0,0 +1,81 @@ +package io.microsphere.test.model; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Unit tests for the Ancestor class + */ +class AncestorTest { + + private Ancestor ancestor; + + @BeforeEach + void setUp() { + ancestor = new Ancestor(); + } + + @Test + void testDefaultConstructor() { + // Verify that the default value of z is false + assertFalse(ancestor.isZ(), "Default value of z should be false"); + } + + @Test + void testSetZTrue() { + // Set z to true and verify + ancestor.setZ(true); + assertTrue(ancestor.isZ(), "Value of z should be true after setting it to true"); + } + + @Test + void testSetZFalse() { + // Explicitly set z to false and verify + ancestor.setZ(false); + assertFalse(ancestor.isZ(), "Value of z should be false after setting it to false"); + } + + @Test + void testSetZToggle() { + // Test toggling the value from default false to true and back to false + assertFalse(ancestor.isZ(), "Initial value should be false"); + + ancestor.setZ(true); + assertTrue(ancestor.isZ(), "Value should be true after first toggle"); + + ancestor.setZ(false); + assertFalse(ancestor.isZ(), "Value should be false after second toggle"); + } + + @Test + void testMultipleInstanceIndependence() { + // Create two instances and verify they maintain independent state + Ancestor ancestor1 = new Ancestor(); + Ancestor ancestor2 = new Ancestor(); + + // Initially both should have false + assertFalse(ancestor1.isZ(), "First instance should initially be false"); + assertFalse(ancestor2.isZ(), "Second instance should initially be false"); + + // Modify only the first instance + ancestor1.setZ(true); + + // Verify that only the first instance changed + assertTrue(ancestor1.isZ(), "First instance should be true after modification"); + assertFalse(ancestor2.isZ(), "Second instance should remain false"); + } + + @Test + void testSerializableImplementation() { + // Test that the class can be instantiated and used as a Serializable object + // This test verifies basic functionality without actual serialization + ancestor.setZ(true); + assertTrue(ancestor.isZ(), "Should properly handle boolean value when used as Serializable"); + + ancestor.setZ(false); + assertFalse(ancestor.isZ(), "Should properly handle boolean value when used as Serializable"); + } +} diff --git a/microsphere-java-test/src/test/java/io/microsphere/test/model/ArrayTypeModelTest.java b/microsphere-java-test/src/test/java/io/microsphere/test/model/ArrayTypeModelTest.java new file mode 100644 index 000000000..ebf9644af --- /dev/null +++ b/microsphere-java-test/src/test/java/io/microsphere/test/model/ArrayTypeModelTest.java @@ -0,0 +1,122 @@ +package io.microsphere.test.model; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static io.microsphere.test.model.Color.BLUE; +import static io.microsphere.test.model.Color.RED; +import static io.microsphere.test.model.Color.YELLOW; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; + +/** + * Unit tests for the ArrayTypeModel class + */ +class ArrayTypeModelTest { + + private ArrayTypeModel model; + + @BeforeEach + void setUp() { + model = new ArrayTypeModel(); + } + + @Test + void testDefaultValues() { + // Verify all array fields are null by default + assertNull(model.getIntegers(), "integers array should be null by default"); + assertNull(model.getStrings(), "strings array should be null by default"); + assertNull(model.getPrimitiveTypeModels(), "primitiveTypeModels array should be null by default"); + assertNull(model.getModels(), "models array should be null by default"); + assertNull(model.getColors(), "colors array should be null by default"); + } + + @Test + void testSetGetIntegers() { + int[] testArray = {1, 2, 3, 4, 5}; + + model.setIntegers(testArray); + assertSame(testArray, model.getIntegers(), "Should return the same array reference that was set"); + + // Verify the contents match + assertArrayEquals(testArray, model.getIntegers(), "Array contents should match the set value"); + } + + @Test + void testSetGetStrings() { + String[] testArray = {"hello", "world", "test"}; + + model.setStrings(testArray); + assertSame(testArray, model.getStrings(), "Should return the same array reference that was set"); + + // Verify the contents match + assertArrayEquals(testArray, model.getStrings(), "Array contents should match the set value"); + } + + @Test + void testSetGetPrimitiveTypeModels() { + PrimitiveTypeModel[] testArray = {new PrimitiveTypeModel(), new PrimitiveTypeModel()}; + + model.setPrimitiveTypeModels(testArray); + assertSame(testArray, model.getPrimitiveTypeModels(), "Should return the same array reference that was set"); + + // Verify the contents match + assertArrayEquals(testArray, model.getPrimitiveTypeModels(), "Array contents should match the set value"); + } + + @Test + void testSetGetModels() { + Model[] testArray = {new Model(), new Model()}; + + model.setModels(testArray); + assertSame(testArray, model.getModels(), "Should return the same array reference that was set"); + + // Verify the contents match + assertArrayEquals(testArray, model.getModels(), "Array contents should match the set value"); + } + + @Test + void testSetGetColors() { + Color[] testArray = {RED, BLUE, YELLOW}; + + model.setColors(testArray); + assertSame(testArray, model.getColors(), "Should return the same array reference that was set"); + + // Verify the contents match + assertArrayEquals(testArray, model.getColors(), "Array contents should match the set value"); + } + + @Test + void testSetNullValues() { + // Test setting each field to null + model.setIntegers(null); + assertNull(model.getIntegers(), "integers should be null after setting to null"); + + model.setStrings(null); + assertNull(model.getStrings(), "strings should be null after setting to null"); + + model.setPrimitiveTypeModels(null); + assertNull(model.getPrimitiveTypeModels(), "primitiveTypeModels should be null after setting to null"); + + model.setModels(null); + assertNull(model.getModels(), "models should be null after setting to null"); + + model.setColors(null); + assertNull(model.getColors(), "colors should be null after setting to null"); + } + + @Test + void testArrayMutability() { + int[] originalArray = {1, 2, 3}; + model.setIntegers(originalArray); + + // Modify the original array + originalArray[0] = 999; + + // Check if the change is reflected in the getter result + assertEquals(999, model.getIntegers()[0], + "Changes to the original array should be reflected since arrays are passed by reference"); + } +} \ No newline at end of file diff --git a/microsphere-java-test/src/test/java/io/microsphere/test/model/CollectionTypeModelTest.java b/microsphere-java-test/src/test/java/io/microsphere/test/model/CollectionTypeModelTest.java new file mode 100644 index 000000000..af3ae9098 --- /dev/null +++ b/microsphere-java-test/src/test/java/io/microsphere/test/model/CollectionTypeModelTest.java @@ -0,0 +1,138 @@ +package io.microsphere.test.model; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Deque; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.Set; + +import static io.microsphere.test.model.Color.BLUE; +import static io.microsphere.test.model.Color.RED; +import static io.microsphere.test.model.Color.YELLOW; +import static java.util.Arrays.asList; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Unit tests for the CollectionTypeModel class + */ +class CollectionTypeModelTest { + + private CollectionTypeModel model; + + @BeforeEach + void setUp() { + model = new CollectionTypeModel(); + } + + @Test + void testDefaultValues() { + // Verify all collection fields are null by default + assertNull(model.getStrings(), "strings collection should be null by default"); + assertNull(model.getColors(), "colors list should be null by default"); + assertNull(model.getPrimitiveTypeModels(), "primitiveTypeModels queue should be null by default"); + assertNull(model.getModels(), "models deque should be null by default"); + assertNull(model.getModelArrays(), "modelArrays set should be null by default"); + } + + @Test + void testSetGetStrings() { + Collection testCollection = asList("hello", "world", "test"); + + model.setStrings(testCollection); + assertSame(testCollection, model.getStrings(), "Should return the same collection reference that was set"); + + // Verify the contents match + assertEquals(testCollection, model.getStrings(), "Collection contents should match the set value"); + } + + @Test + void testSetGetColors() { + List testList = asList(RED, BLUE, YELLOW); + + model.setColors(testList); + assertSame(testList, model.getColors(), "Should return the same list reference that was set"); + + // Verify the contents match + assertEquals(testList, model.getColors(), "List contents should match the set value"); + } + + @Test + void testSetGetPrimitiveTypeModels() { + Queue testQueue = new LinkedList<>(); + testQueue.add(new PrimitiveTypeModel()); + testQueue.add(new PrimitiveTypeModel()); + + model.setPrimitiveTypeModels(testQueue); + assertSame(testQueue, model.getPrimitiveTypeModels(), "Should return the same queue reference that was set"); + + // Verify the contents match + assertEquals(testQueue, model.getPrimitiveTypeModels(), "Queue contents should match the set value"); + } + + @Test + void testSetGetModels() { + Deque testDeque = new LinkedList<>(); + testDeque.add(new Model()); + testDeque.add(new Model()); + + model.setModels(testDeque); + assertSame(testDeque, model.getModels(), "Should return the same deque reference that was set"); + + // Verify the contents match + assertEquals(testDeque, model.getModels(), "Deque contents should match the set value"); + } + + @Test + void testSetGetModelArrays() { + Set testSet = new HashSet<>(); + testSet.add(new Model[]{new Model(), new Model()}); + testSet.add(new Model[]{new Model()}); + + model.setModelArrays(testSet); + assertSame(testSet, model.getModelArrays(), "Should return the same set reference that was set"); + + // Verify the contents match + assertEquals(testSet, model.getModelArrays(), "Set contents should match the set value"); + } + + @Test + void testSetNullValues() { + // Test setting each field to null + model.setStrings(null); + assertNull(model.getStrings(), "strings should be null after setting to null"); + + model.setColors(null); + assertNull(model.getColors(), "colors should be null after setting to null"); + + model.setPrimitiveTypeModels(null); + assertNull(model.getPrimitiveTypeModels(), "primitiveTypeModels should be null after setting to null"); + + model.setModels(null); + assertNull(model.getModels(), "models should be null after setting to null"); + + model.setModelArrays(null); + assertNull(model.getModelArrays(), "modelArrays should be null after setting to null"); + } + + @Test + void testCollectionMutability() { + List originalList = new ArrayList<>(asList(RED, BLUE)); + model.setColors(originalList); + + // Modify the original collection + originalList.add(RED); + + // Check if the change is reflected in the getter result + assertTrue(model.getColors().contains(RED), + "Changes to the original collection should be reflected since collections are passed by reference"); + } +} diff --git a/microsphere-java-test/src/test/java/io/microsphere/test/model/ColorTest.java b/microsphere-java-test/src/test/java/io/microsphere/test/model/ColorTest.java new file mode 100644 index 000000000..9f8f0cfde --- /dev/null +++ b/microsphere-java-test/src/test/java/io/microsphere/test/model/ColorTest.java @@ -0,0 +1,103 @@ +package io.microsphere.test.model; + +import org.junit.jupiter.api.Test; + +import static io.microsphere.test.model.Color.BLUE; +import static io.microsphere.test.model.Color.RED; +import static io.microsphere.test.model.Color.YELLOW; +import static java.util.Arrays.asList; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Unit tests for the Color enum + */ +class ColorTest { + + @Test + void testEnumValues() { + // Verify that all enum constants exist and are accessible + assertNotNull(RED, "RED color should exist"); + assertNotNull(YELLOW, "YELLOW color should exist"); + assertNotNull(BLUE, "BLUE color should exist"); + } + + @Test + void testGetValueMethod() { + // Verify the value associated with each color + assertEquals(1, RED.getValue(), "RED should have value 1"); + assertEquals(2, YELLOW.getValue(), "YELLOW should have value 2"); + assertEquals(3, BLUE.getValue(), "BLUE should have value 3"); + } + + @Test + void testToStringMethod() { + // Verify the string representation of each color + String redString = RED.toString(); + assertTrue(redString.contains("Color{value=1}"), "RED toString should contain value=1"); + assertTrue(redString.endsWith("RED"), "RED toString should end with RED"); + + String yellowString = YELLOW.toString(); + assertTrue(yellowString.contains("Color{value=2}"), "YELLOW toString should contain value=2"); + assertTrue(yellowString.endsWith("YELLOW"), "YELLOW toString should end with YELLOW"); + + String blueString = BLUE.toString(); + assertTrue(blueString.contains("Color{value=3}"), "BLUE toString should contain value=3"); + assertTrue(blueString.endsWith("BLUE"), "BLUE toString should end with BLUE"); + } + + @Test + void testEnumOrdinality() { + // Verify that enum constants have expected ordinal positions + assertEquals(0, RED.ordinal(), "RED should be at ordinal position 0"); + assertEquals(1, YELLOW.ordinal(), "YELLOW should be at ordinal position 1"); + assertEquals(2, BLUE.ordinal(), "BLUE should be at ordinal position 2"); + } + + @Test + void testEnumName() { + // Verify that enum constants have correct names + assertEquals("RED", RED.name(), "RED name should be 'RED'"); + assertEquals("YELLOW", YELLOW.name(), "YELLOW name should be 'YELLOW'"); + assertEquals("BLUE", BLUE.name(), "BLUE name should be 'BLUE'"); + } + + @Test + void testEnumEquality() { + // Verify that enum equality works correctly + assertEquals(RED, RED, "RED should equal itself"); + assertEquals(YELLOW, YELLOW, "YELLOW should equal itself"); + assertEquals(BLUE, BLUE, "BLUE should equal itself"); + + assertNotEquals(RED, BLUE, "RED should not equal BLUE"); + assertNotEquals(RED, YELLOW, "RED should not equal YELLOW"); + assertNotEquals(BLUE, YELLOW, "BLUE should not equal YELLOW"); + } + + @Test + void testValueImmutability() { + // Verify that the value cannot be changed (as it's final) + int redValue = RED.getValue(); + int yellowValue = YELLOW.getValue(); + int blueValue = BLUE.getValue(); + + // Values should remain constant across multiple calls + assertEquals(redValue, RED.getValue(), "RED value should be immutable"); + assertEquals(yellowValue, YELLOW.getValue(), "YELLOW value should be immutable"); + assertEquals(blueValue, BLUE.getValue(), "BLUE value should be immutable"); + } + + @Test + void testAllEnumConstantsExist() { + // Verify that we can retrieve all enum constants + Color[] allColors = Color.values(); + assertEquals(3, allColors.length, "There should be exactly 3 color constants"); + + // Verify that all expected colors are present + assertTrue(asList(allColors).contains(RED), "All colors should include RED"); + assertTrue(asList(allColors).contains(YELLOW), "All colors should include YELLOW"); + assertTrue(asList(allColors).contains(BLUE), "All colors should include BLUE"); + } +} diff --git a/microsphere-java-test/src/test/java/io/microsphere/test/model/ConfigurationPropertyModelTest.java b/microsphere-java-test/src/test/java/io/microsphere/test/model/ConfigurationPropertyModelTest.java new file mode 100644 index 000000000..4218d3d43 --- /dev/null +++ b/microsphere-java-test/src/test/java/io/microsphere/test/model/ConfigurationPropertyModelTest.java @@ -0,0 +1,152 @@ +package io.microsphere.test.model; + +import io.microsphere.annotation.ConfigurationProperty; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Unit tests for the ConfigurationPropertyModel class + */ +class ConfigurationPropertyModelTest { + + private ConfigurationPropertyModel model; + + @BeforeEach + void setUp() { + model = new ConfigurationPropertyModel(); + } + + @Test + void testDefaultValues() { + // Verify all fields have their default values + assertNull(model.getName(), "name should be null by default"); + assertNull(model.getType(), "type should be null by default"); + assertNull(model.getDefaultValue(), "defaultValue should be null by default"); + assertFalse(model.isRequired(), "required should be false by default"); + assertNull(model.getDescription(), "description should be null by default"); + } + + @Test + void testSetNameAndGet() { + String testName = "test.config.property"; + model.setName(testName); + assertEquals(testName, model.getName(), "getName should return the set value"); + } + + @Test + void testSetTypeAndGet() { + Class testType = String.class; + model.setType(testType); + assertEquals(testType, model.getType(), "getType should return the set value"); + } + + @Test + void testSetDefaultValueAndGet() { + String testDefaultValue = "default_value"; + model.setDefaultValue(testDefaultValue); + assertEquals(testDefaultValue, model.getDefaultValue(), "getDefaultValue should return the set value"); + } + + @Test + void testSetRequiredAndGet() { + model.setRequired(true); + assertTrue(model.isRequired(), "isRequired should return true after setting to true"); + + model.setRequired(false); + assertFalse(model.isRequired(), "isRequired should return false after setting to false"); + } + + @Test + void testSetDescriptionAndGet() { + String testDescription = "This is a test configuration property"; + model.setDescription(testDescription); + assertEquals(testDescription, model.getDescription(), "getDescription should return the set value"); + } + + @Test + void testConfigurationPropertyAnnotations() { + // Test that the ConfigurationProperty annotations are present on the fields + java.lang.reflect.Field[] fields = ConfigurationPropertyModel.class.getDeclaredFields(); + + boolean hasNameAnnotation = false; + boolean hasTypeAnnotation = false; + boolean hasDefaultValueAnnotation = false; + boolean hasRequiredAnnotation = false; + boolean hasDescriptionAnnotation = false; + + for (java.lang.reflect.Field field : fields) { + if (field.isAnnotationPresent(ConfigurationProperty.class)) { + ConfigurationProperty annotation = field.getAnnotation(ConfigurationProperty.class); + + switch (field.getName()) { + case "name": + if ("microsphere.annotation.processor.model.name".equals(annotation.name())) { + hasNameAnnotation = true; + } + break; + case "type": + if ("microsphere.annotation.processor.model.type".equals(annotation.name())) { + hasTypeAnnotation = true; + } + break; + case "defaultValue": + if ("microsphere.annotation.processor.model.default-value".equals(annotation.name())) { + hasDefaultValueAnnotation = true; + } + break; + case "required": + if ("microsphere.annotation.processor.model.required".equals(annotation.name())) { + hasRequiredAnnotation = true; + } + break; + case "description": + if ("microsphere.annotation.processor.model.description".equals(annotation.name())) { + hasDescriptionAnnotation = true; + } + break; + } + } + } + + assertTrue(hasNameAnnotation, "name field should have ConfigurationProperty annotation with correct name"); + assertTrue(hasTypeAnnotation, "type field should have ConfigurationProperty annotation with correct name"); + assertTrue(hasDefaultValueAnnotation, "defaultValue field should have ConfigurationProperty annotation with correct name"); + assertTrue(hasRequiredAnnotation, "required field should have ConfigurationProperty annotation with correct name"); + assertTrue(hasDescriptionAnnotation, "description field should have ConfigurationProperty annotation with correct name"); + } + + @Test + void testSetAllProperties() { + // Test setting all properties and verifying they are returned correctly + model.setName("full.test.name"); + model.setType(Integer.class); + model.setDefaultValue("42"); + model.setRequired(true); + model.setDescription("Complete test configuration"); + + assertEquals("full.test.name", model.getName(), "Name should match set value"); + assertEquals(Integer.class, model.getType(), "Type should match set value"); + assertEquals("42", model.getDefaultValue(), "DefaultValue should match set value"); + assertTrue(model.isRequired(), "Required should match set value"); + assertEquals("Complete test configuration", model.getDescription(), "Description should match set value"); + } + + @Test + void testNullValueHandling() { + // Test setting fields to null + model.setName(null); + model.setType(null); + model.setDefaultValue(null); + model.setDescription(null); + + assertNull(model.getName(), "Name should be null"); + assertNull(model.getType(), "Type should be null"); + assertNull(model.getDefaultValue(), "DefaultValue should be null"); + assertNull(model.getDescription(), "Description should be null"); + } +} diff --git a/microsphere-java-test/src/test/java/io/microsphere/test/model/MapTypeModelTest.java b/microsphere-java-test/src/test/java/io/microsphere/test/model/MapTypeModelTest.java new file mode 100644 index 000000000..9640d802c --- /dev/null +++ b/microsphere-java-test/src/test/java/io/microsphere/test/model/MapTypeModelTest.java @@ -0,0 +1,138 @@ +package io.microsphere.test.model; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; +import java.util.NavigableMap; +import java.util.SortedMap; +import java.util.TreeMap; + +import static io.microsphere.test.model.Color.BLUE; +import static io.microsphere.test.model.Color.RED; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Unit tests for the MapTypeModel class + */ +class MapTypeModelTest { + + private MapTypeModel model; + + @BeforeEach + void setUp() { + model = new MapTypeModel(); + } + + @Test + void testDefaultValues() { + // Verify all map fields are null by default + assertNull(model.getStrings(), "strings map should be null by default"); + assertNull(model.getColors(), "colors sorted map should be null by default"); + assertNull(model.getPrimitiveTypeModels(), "primitiveTypeModels navigable map should be null by default"); + assertNull(model.getModels(), "models hash map should be null by default"); + assertNull(model.getModelArrays(), "modelArrays tree map should be null by default"); + } + + @Test + void testSetGetStrings() { + Map testMap = new HashMap<>(); + testMap.put("key1", "value1"); + testMap.put("key2", "value2"); + + model.setStrings(testMap); + assertSame(testMap, model.getStrings(), "Should return the same map reference that was set"); + + // Verify the contents match + assertEquals(testMap, model.getStrings(), "Map contents should match the set value"); + } + + @Test + void testSetGetColors() { + SortedMap testMap = new TreeMap<>(); + testMap.put("red_key", RED); + testMap.put("blue_key", BLUE); + + model.setColors(testMap); + assertSame(testMap, model.getColors(), "Should return the same map reference that was set"); + + // Verify the contents match + assertEquals(testMap, model.getColors(), "SortedMap contents should match the set value"); + } + + @Test + void testSetGetPrimitiveTypeModels() { + NavigableMap testMap = new TreeMap<>(); + testMap.put(RED, new PrimitiveTypeModel()); + testMap.put(BLUE, new PrimitiveTypeModel()); + + model.setPrimitiveTypeModels(testMap); + assertSame(testMap, model.getPrimitiveTypeModels(), "Should return the same map reference that was set"); + + // Verify the contents match + assertEquals(testMap, model.getPrimitiveTypeModels(), "NavigableMap contents should match the set value"); + } + + @Test + void testSetGetModels() { + HashMap testMap = new HashMap<>(); + testMap.put("model1", new Model()); + testMap.put("model2", new Model()); + + model.setModels(testMap); + assertSame(testMap, model.getModels(), "Should return the same map reference that was set"); + + // Verify the contents match + assertEquals(testMap, model.getModels(), "HashMap contents should match the set value"); + } + + @Test + void testSetGetModelArrays() { + TreeMap testMap = new TreeMap<>((a, b) -> 1); // Using custom comparator to avoid issues with PrimitiveTypeModel not implementing Comparable + testMap.put(new PrimitiveTypeModel(), new Model[]{new Model()}); + testMap.put(new PrimitiveTypeModel(), new Model[]{new Model(), new Model()}); + + model.setModelArrays(testMap); + assertSame(testMap, model.getModelArrays(), "Should return the same map reference that was set"); + + // Verify the contents match + assertEquals(testMap, model.getModelArrays(), "TreeMap contents should match the set value"); + } + + @Test + void testSetNullValues() { + // Test setting each field to null + model.setStrings(null); + assertNull(model.getStrings(), "strings should be null after setting to null"); + + model.setColors(null); + assertNull(model.getColors(), "colors should be null after setting to null"); + + model.setPrimitiveTypeModels(null); + assertNull(model.getPrimitiveTypeModels(), "primitiveTypeModels should be null after setting to null"); + + model.setModels(null); + assertNull(model.getModels(), "models should be null after setting to null"); + + model.setModelArrays(null); + assertNull(model.getModelArrays(), "modelArrays should be null after setting to null"); + } + + @Test + void testMapMutability() { + Map originalMap = new HashMap<>(); + originalMap.put("initial", "value"); + model.setStrings(originalMap); + + // Modify the original map + originalMap.put("added", "new_value"); + + // Check if the change is reflected in the getter result + assertTrue(model.getStrings().containsKey("added"), + "Changes to the original map should be reflected since maps are passed by reference"); + } +} diff --git a/microsphere-java-test/src/test/java/io/microsphere/test/model/ModelTest.java b/microsphere-java-test/src/test/java/io/microsphere/test/model/ModelTest.java new file mode 100644 index 000000000..5a9b63b28 --- /dev/null +++ b/microsphere-java-test/src/test/java/io/microsphere/test/model/ModelTest.java @@ -0,0 +1,116 @@ +package io.microsphere.test.model; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.concurrent.TimeUnit; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Unit tests for the Model class + */ +class ModelTest { + + private Model model; + + @BeforeEach + void setUp() { + model = new Model(); + } + + @Test + void testDefaultValues() { + // Verify all primitive fields have their default values + assertEquals(0.0f, model.getF(), "float field f should be 0.0f by default"); + assertEquals(0.0d, model.getD(), "double field d should be 0.0d by default"); + + // Verify all object fields are null by default + assertNull(model.getTu(), "TimeUnit field tu should be null by default"); + assertNull(model.getStr(), "String field str should be null by default"); + assertNull(model.getBi(), "BigInteger field bi should be null by default"); + assertNull(model.getBd(), "BigDecimal field bd should be null by default"); + } + + @Test + void testSetGetFloat() { + float testValue = 3.14f; + model.setF(testValue); + assertEquals(testValue, model.getF(), "getF should return the set value"); + } + + @Test + void testSetGetDouble() { + double testValue = 2.71828d; + model.setD(testValue); + assertEquals(testValue, model.getD(), "getD should return the set value"); + } + + @Test + void testSetGetTimeUnit() { + TimeUnit testValue = TimeUnit.SECONDS; + model.setTu(testValue); + assertEquals(testValue, model.getTu(), "getTu should return the set value"); + } + + @Test + void testSetGetString() { + String testValue = "Hello World"; + model.setStr(testValue); + assertEquals(testValue, model.getStr(), "getStr should return the set value"); + } + + @Test + void testSetGetBigInteger() { + BigInteger testValue = new BigInteger("123456789012345678901234567890"); + model.setBi(testValue); + assertEquals(testValue, model.getBi(), "getBi should return the set value"); + } + + @Test + void testSetGetBigDecimal() { + BigDecimal testValue = new BigDecimal("1234567890.12345678901234567890"); + model.setBd(testValue); + assertEquals(testValue, model.getBd(), "getBd should return the set value"); + } + + @Test + void testInheritanceFromParent() { + // Verify that the model inherits from Parent class + assertTrue(model instanceof Parent, "Model should extend Parent class"); + } + + @Test + void testMultipleValueChanges() { + // Test changing values multiple times + model.setF(1.0f); + assertEquals(1.0f, model.getF(), "f should be 1.0f"); + + model.setF(2.0f); + assertEquals(2.0f, model.getF(), "f should be 2.0f after second assignment"); + + model.setD(10.0d); + assertEquals(10.0d, model.getD(), "d should be 10.0d"); + + model.setD(20.0d); + assertEquals(20.0d, model.getD(), "d should be 20.0d after second assignment"); + } + + @Test + void testNullHandling() { + // Test setting object fields to null + model.setTu(null); + model.setStr(null); + model.setBi(null); + model.setBd(null); + + assertNull(model.getTu(), "tu should be null after setting to null"); + assertNull(model.getStr(), "str should be null after setting to null"); + assertNull(model.getBi(), "bi should be null after setting to null"); + assertNull(model.getBd(), "bd should be null after setting to null"); + } +} diff --git a/microsphere-java-test/src/test/java/io/microsphere/test/model/ParentTest.java b/microsphere-java-test/src/test/java/io/microsphere/test/model/ParentTest.java new file mode 100644 index 000000000..30d489e6e --- /dev/null +++ b/microsphere-java-test/src/test/java/io/microsphere/test/model/ParentTest.java @@ -0,0 +1,86 @@ +package io.microsphere.test.model; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Unit tests for the Parent class + */ +class ParentTest { + + private Parent parent; + + @BeforeEach + void setUp() { + parent = new Parent(); + } + + @Test + void testDefaultValues() { + // Verify all primitive fields have their default values + assertEquals((byte) 0, parent.getB(), "byte field b should be 0 by default"); + assertEquals((short) 0, parent.getS(), "short field s should be 0 by default"); + assertEquals(0, parent.getI(), "int field i should be 0 by default"); + assertEquals(0L, parent.getL(), "long field l should be 0L by default"); + } + + @Test + void testSetGetByte() { + byte testValue = (byte) 42; + parent.setB(testValue); + assertEquals(testValue, parent.getB(), "getB should return the set value"); + } + + @Test + void testSetGetShort() { + short testValue = (short) 1000; + parent.setS(testValue); + assertEquals(testValue, parent.getS(), "getS should return the set value"); + } + + @Test + void testSetGetInt() { + int testValue = 123456; + parent.setI(testValue); + assertEquals(testValue, parent.getI(), "getI should return the set value"); + } + + @Test + void testSetGetLong() { + long testValue = 9876543210L; + parent.setL(testValue); + assertEquals(testValue, parent.getL(), "getL should return the set value"); + } + + @Test + void testInheritanceFromAncestor() { + // Verify that the parent inherits from Ancestor class + assertTrue(parent instanceof Ancestor, "Parent should extend Ancestor class"); + + // Test inherited functionality + assertFalse(parent.isZ(), "Should inherit default z value of false from Ancestor"); + + parent.setZ(true); + assertTrue(parent.isZ(), "Should be able to modify inherited z field"); + } + + @Test + void testMultipleValueChanges() { + // Test changing values multiple times + parent.setB((byte) 1); + assertEquals((byte) 1, parent.getB(), "b should be 1"); + + parent.setB((byte) 2); + assertEquals((byte) 2, parent.getB(), "b should be 2 after second assignment"); + + parent.setI(100); + assertEquals(100, parent.getI(), "i should be 100"); + + parent.setI(200); + assertEquals(200, parent.getI(), "i should be 200 after second assignment"); + } +} diff --git a/microsphere-java-test/src/test/java/io/microsphere/test/model/PrimitiveTypeModelTest.java b/microsphere-java-test/src/test/java/io/microsphere/test/model/PrimitiveTypeModelTest.java new file mode 100644 index 000000000..1f28bcb4d --- /dev/null +++ b/microsphere-java-test/src/test/java/io/microsphere/test/model/PrimitiveTypeModelTest.java @@ -0,0 +1,81 @@ +package io.microsphere.test.model; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; + +/** + * Unit tests for the PrimitiveTypeModel class + */ +class PrimitiveTypeModelTest { + + private PrimitiveTypeModel model; + + @BeforeEach + void setUp() { + model = new PrimitiveTypeModel(); + } + + @Test + void testDefaultValues() { + // Verify all primitive fields have their default values + assertFalse(model.isZ(), "boolean field z should be false by default"); + assertEquals((byte) 0, model.getB(), "byte field b should be 0 by default"); + assertEquals('\u0000', model.getC(), "char field c should be null character by default"); + assertEquals((short) 0, model.getS(), "short field s should be 0 by default"); + assertEquals(0, model.getI(), "int field i should be 0 by default"); + assertEquals(0L, model.getL(), "long field l should be 0L by default"); + assertEquals(0.0f, model.getF(), "float field f should be 0.0f by default"); + assertEquals(0.0d, model.getD(), "double field d should be 0.0d by default"); + } + + @Test + void testBooleanField() { + // Test boolean field specifically since it uses 'is' prefix instead of 'get' + assertFalse(model.isZ(), "Initial value should be false"); + } + + @Test + void testPrimitiveTypesRange() { + // Test various ranges for different primitive types + PrimitiveTypeModel testModel = new PrimitiveTypeModel(); + + // Boolean + // Cannot set values directly as there are no setters, but we can verify the default + + // Byte range (-128 to 127) + byte minByte = Byte.MIN_VALUE; + byte maxByte = Byte.MAX_VALUE; + + // Char range (0 to 65535) + char minChar = Character.MIN_VALUE; + char maxChar = Character.MAX_VALUE; + + // Short range (-32768 to 32767) + short minShort = Short.MIN_VALUE; + short maxShort = Short.MAX_VALUE; + + // Int range + int minInt = Integer.MIN_VALUE; + int maxInt = Integer.MAX_VALUE; + + // Long range + long minLong = Long.MIN_VALUE; + long maxLong = Long.MAX_VALUE; + + // Float range + float minFloat = Float.MIN_VALUE; + float maxFloat = Float.MAX_VALUE; + + // Double range + double minDouble = Double.MIN_VALUE; + double maxDouble = Double.MAX_VALUE; + + // These are just to ensure the getters work with different possible values + // Since there are no setters, we're just validating the getters return values + assertEquals(0, testModel.getI(), "Integer field should have default value"); + assertEquals(0.0f, testModel.getF(), "Float field should have default value"); + } +} diff --git a/microsphere-java-test/src/test/java/io/microsphere/test/model/SimpleTypeModelTest.java b/microsphere-java-test/src/test/java/io/microsphere/test/model/SimpleTypeModelTest.java new file mode 100644 index 000000000..6a0d24251 --- /dev/null +++ b/microsphere-java-test/src/test/java/io/microsphere/test/model/SimpleTypeModelTest.java @@ -0,0 +1,182 @@ +package io.microsphere.test.model; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Date; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +/** + * Unit tests for the SimpleTypeModel class + */ +class SimpleTypeModelTest { + + private SimpleTypeModel model; + + @BeforeEach + void setUp() { + model = new SimpleTypeModel(); + } + + @Test + void testDefaultValues() { + // Verify all object fields are null by default + assertNull(model.getV(), "Void field v should be null by default"); + assertNull(model.getZ(), "Boolean field z should be null by default"); + assertNull(model.getC(), "Character field c should be null by default"); + assertNull(model.getB(), "Byte field b should be null by default"); + assertNull(model.getS(), "Short field s should be null by default"); + assertNull(model.getI(), "Integer field i should be null by default"); + assertNull(model.getL(), "Long field l should be null by default"); + assertNull(model.getF(), "Float field f should be null by default"); + assertNull(model.getD(), "Double field d should be null by default"); + assertNull(model.getStr(), "String field str should be null by default"); + assertNull(model.getBd(), "BigDecimal field bd should be null by default"); + assertNull(model.getBi(), "BigInteger field bi should be null by default"); + assertNull(model.getDt(), "Date field dt should be null by default"); + } + + @Test + void testSetGetVoid() { + // Void is always null, so setting it to null should work + model.setV(null); + assertNull(model.getV(), "Void should always be null"); + } + + @Test + void testSetGetBoolean() { + Boolean testValue = Boolean.TRUE; + model.setZ(testValue); + assertEquals(testValue, model.getZ(), "getZ should return the set value"); + + model.setZ(Boolean.FALSE); + assertEquals(Boolean.FALSE, model.getZ(), "getZ should return the set value"); + } + + @Test + void testSetGetCharacter() { + Character testValue = 'A'; + model.setC(testValue); + assertEquals(testValue, model.getC(), "getC should return the set value"); + } + + @Test + void testSetGetByte() { + Byte testValue = (byte) 42; + model.setB(testValue); + assertEquals(testValue, model.getB(), "getB should return the set value"); + } + + @Test + void testSetGetShort() { + Short testValue = (short) 1000; + model.setS(testValue); + assertEquals(testValue, model.getS(), "getS should return the set value"); + } + + @Test + void testSetGetInteger() { + Integer testValue = 123456; + model.setI(testValue); + assertEquals(testValue, model.getI(), "getI should return the set value"); + } + + @Test + void testSetGetLong() { + Long testValue = 9876543210L; + model.setL(testValue); + assertEquals(testValue, model.getL(), "getL should return the set value"); + } + + @Test + void testSetGetFloat() { + Float testValue = 3.14f; + model.setF(testValue); + assertEquals(testValue, model.getF(), "getF should return the set value"); + } + + @Test + void testSetGetDouble() { + Double testValue = 2.71828d; + model.setD(testValue); + assertEquals(testValue, model.getD(), "getD should return the set value"); + } + + @Test + void testSetGetString() { + String testValue = "Hello World"; + model.setStr(testValue); + assertEquals(testValue, model.getStr(), "getStr should return the set value"); + } + + @Test + void testSetGetBigDecimal() { + BigDecimal testValue = new BigDecimal("1234567890.12345678901234567890"); + model.setBd(testValue); + assertEquals(testValue, model.getBd(), "getBd should return the set value"); + } + + @Test + void testSetGetBigInteger() { + BigInteger testValue = new BigInteger("123456789012345678901234567890"); + model.setBi(testValue); + assertEquals(testValue, model.getBi(), "getBi should return the set value"); + } + + @Test + void testSetGetDate() { + Date testValue = new Date(); + model.setDt(testValue); + assertEquals(testValue, model.getDt(), "getDt should return the set value"); + } + + @Test + void testNullHandling() { + // Test setting all fields to null + model.setZ(null); + model.setC(null); + model.setB(null); + model.setS(null); + model.setI(null); + model.setL(null); + model.setF(null); + model.setD(null); + model.setStr(null); + model.setBd(null); + model.setBi(null); + model.setDt(null); + + assertNull(model.getZ(), "z should be null after setting to null"); + assertNull(model.getC(), "c should be null after setting to null"); + assertNull(model.getB(), "b should be null after setting to null"); + assertNull(model.getS(), "s should be null after setting to null"); + assertNull(model.getI(), "i should be null after setting to null"); + assertNull(model.getL(), "l should be null after setting to null"); + assertNull(model.getF(), "f should be null after setting to null"); + assertNull(model.getD(), "d should be null after setting to null"); + assertNull(model.getStr(), "str should be null after setting to null"); + assertNull(model.getBd(), "bd should be null after setting to null"); + assertNull(model.getBi(), "bi should be null after setting to null"); + assertNull(model.getDt(), "dt should be null after setting to null"); + } + + @Test + void testMultipleValueChanges() { + // Test changing values multiple times + model.setI(100); + assertEquals(Integer.valueOf(100), model.getI(), "i should be 100"); + + model.setI(200); + assertEquals(Integer.valueOf(200), model.getI(), "i should be 200 after second assignment"); + + model.setStr("first"); + assertEquals("first", model.getStr(), "str should be 'first'"); + + model.setStr("second"); + assertEquals("second", model.getStr(), "str should be 'second' after second assignment"); + } +} diff --git a/microsphere-java-test/src/test/java/io/microsphere/test/model/StringArrayListTest.java b/microsphere-java-test/src/test/java/io/microsphere/test/model/StringArrayListTest.java new file mode 100644 index 000000000..cc417fa20 --- /dev/null +++ b/microsphere-java-test/src/test/java/io/microsphere/test/model/StringArrayListTest.java @@ -0,0 +1,137 @@ +package io.microsphere.test.model; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Unit tests for the StringArrayList class + */ +class StringArrayListTest { + + private StringArrayList stringArrayList; + + @BeforeEach + void setUp() { + stringArrayList = new StringArrayList(); + } + + @Test + void testDefaultConstructor() { + // Verify that the StringArrayList can be instantiated and is empty initially + assertNotNull(stringArrayList, "StringArrayList should be instantiated successfully"); + assertTrue(stringArrayList.isEmpty(), "StringArrayList should be empty by default"); + assertEquals(0, stringArrayList.size(), "StringArrayList size should be 0 by default"); + } + + @Test + void testAddAndGetSize() { + // Test adding elements and checking size + stringArrayList.add("element1"); + assertEquals(1, stringArrayList.size(), "Size should be 1 after adding one element"); + + stringArrayList.add("element2"); + assertEquals(2, stringArrayList.size(), "Size should be 2 after adding two elements"); + } + + @Test + void testAddAndGetElements() { + // Test adding elements and retrieving them + String element1 = "Hello"; + String element2 = "World"; + String element3 = "Test"; + + stringArrayList.add(element1); + stringArrayList.add(element2); + stringArrayList.add(element3); + + assertEquals(element1, stringArrayList.get(0), "Element at index 0 should match added value"); + assertEquals(element2, stringArrayList.get(1), "Element at index 1 should match added value"); + assertEquals(element3, stringArrayList.get(2), "Element at index 2 should match added value"); + } + + @Test + void testAddAll() { + // Test adding multiple elements at once + String[] elements = {"item1", "item2", "item3"}; + + boolean result = stringArrayList.addAll(Arrays.asList(elements)); + assertTrue(result, "addAll should return true when elements are added"); + + assertEquals(3, stringArrayList.size(), "Size should match number of added elements"); + assertEquals("item1", stringArrayList.get(0), "First element should match"); + assertEquals("item2", stringArrayList.get(1), "Second element should match"); + assertEquals("item3", stringArrayList.get(2), "Third element should match"); + } + + @Test + void testRemoveElement() { + // Test removing elements + stringArrayList.add("element1"); + stringArrayList.add("element2"); + + boolean removed = stringArrayList.remove("element1"); + assertTrue(removed, "Should return true when element is successfully removed"); + assertEquals(1, stringArrayList.size(), "Size should decrease after removal"); + assertEquals("element2", stringArrayList.get(0), "Remaining element should still be accessible"); + } + + @Test + void testClear() { + // Test clearing all elements + stringArrayList.add("element1"); + stringArrayList.add("element2"); + stringArrayList.add("element3"); + + assertEquals(3, stringArrayList.size(), "Size should be 3 before clear"); + + stringArrayList.clear(); + + assertTrue(stringArrayList.isEmpty(), "List should be empty after clear"); + assertEquals(0, stringArrayList.size(), "Size should be 0 after clear"); + } + + @Test + void testContains() { + // Test contains functionality + String element = "test_element"; + stringArrayList.add(element); + + assertTrue(stringArrayList.contains(element), "List should contain the added element"); + assertFalse(stringArrayList.contains("non_existent"), "List should not contain non-existent element"); + } + + @Test + void testIterator() { + // Test iterator functionality + String[] elements = {"a", "b", "c"}; + stringArrayList.addAll(Arrays.asList(elements)); + + Iterator iterator = stringArrayList.iterator(); + int index = 0; + + while (iterator.hasNext() && index < elements.length) { + String nextElement = iterator.next(); + assertEquals(elements[index], nextElement, "Iterator should return elements in order"); + index++; + } + + assertFalse(iterator.hasNext(), "Iterator should be exhausted after processing all elements"); + } + + @Test + void testInheritanceFromArrayList() { + // Verify that StringArrayList properly extends ArrayList + assertTrue(stringArrayList instanceof ArrayList, "StringArrayList should extend ArrayList"); + assertTrue(stringArrayList instanceof java.util.List, "StringArrayList should implement List interface"); + assertTrue(stringArrayList instanceof java.util.Collection, "StringArrayList should implement Collection interface"); + } +} diff --git a/microsphere-java-test/src/test/java/io/microsphere/test/service/DefaultTestServiceTest.java b/microsphere-java-test/src/test/java/io/microsphere/test/service/DefaultTestServiceTest.java new file mode 100644 index 000000000..a7713e79a --- /dev/null +++ b/microsphere-java-test/src/test/java/io/microsphere/test/service/DefaultTestServiceTest.java @@ -0,0 +1,83 @@ +package io.microsphere.test.service; + +import io.microsphere.test.model.Model; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.concurrent.TimeUnit; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; + +/** + * Unit tests for the DefaultTestService class. + */ +class DefaultTestServiceTest { + + private DefaultTestService defaultTestService; + + @BeforeEach + void setUp() { + defaultTestService = new DefaultTestService(); + } + + /** + * Test the echo method. + * Verifies that the method correctly prefixes the input message with "[ECHO] ". + */ + @Test + void testEcho() { + String input = "Hello, World!"; + String expectedOutput = "[ECHO] Hello, World!"; + String actualOutput = defaultTestService.echo(input); + assertEquals(expectedOutput, actualOutput, "The echo method should prefix the message with '[ECHO] '."); + } + + /** + * Test the model method. + * Verifies that the method returns the same Model object that was passed in. + */ + @Test + void testModel() { + Model inputModel = new Model(); + Model outputModel = defaultTestService.model(inputModel); + assertSame(inputModel, outputModel, "The model method should return the same Model object."); + } + + /** + * Test the testPrimitive method. + * Currently, this method returns null, so the test verifies that null is returned. + */ + @Test + void testTestPrimitive() { + boolean z = true; + int i = 42; + String result = defaultTestService.testPrimitive(z, i); + assertNull(result, "The testPrimitive method should return null."); + } + + /** + * Test the testEnum method. + * Currently, this method returns null, so the test verifies that null is returned. + */ + @Test + void testTestEnum() { + TimeUnit timeUnit = TimeUnit.SECONDS; + Model result = defaultTestService.testEnum(timeUnit); + assertNull(result, "The testEnum method should return null."); + } + + /** + * Test the testArray method. + * Currently, this method returns null, so the test verifies that null is returned. + */ + @Test + void testTestArray() { + String[] strArray = {"a", "b", "c"}; + int[] intArray = {1, 2, 3}; + Model[] modelArray = {new Model(), new Model()}; + String result = defaultTestService.testArray(strArray, intArray, modelArray); + assertNull(result, "The testArray method should return null."); + } +} diff --git a/microsphere-java-test/src/test/java/io/microsphere/test/service/GenericTestServiceTest.java b/microsphere-java-test/src/test/java/io/microsphere/test/service/GenericTestServiceTest.java new file mode 100644 index 000000000..d97ca6011 --- /dev/null +++ b/microsphere-java-test/src/test/java/io/microsphere/test/service/GenericTestServiceTest.java @@ -0,0 +1,58 @@ +package io.microsphere.test.service; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Unit tests for the GenericTestService class. + */ +class GenericTestServiceTest { + + private GenericTestService genericTestService; + + @BeforeEach + void setUp() { + genericTestService = new GenericTestService(); + } + + /** + * Test the echo method. + * Verifies that the method correctly prefixes the input message with "[ECHO] ". + */ + @Test + void testEcho() { + String input = "Hello, World!"; + String expectedOutput = "[ECHO] Hello, World!"; + String actualOutput = genericTestService.echo(input); + assertEquals(expectedOutput, actualOutput, "The echo method should prefix the message with '[ECHO] '."); + } + + /** + * Test inheritance from DefaultTestService. + * Verifies that methods from the parent class are accessible and functional. + */ + @Test + void testInheritedMethods() { + // Example: Testing a method inherited from DefaultTestService + // Assuming DefaultTestService has a method like model(Model model) + // Uncomment and adapt the following lines if such a method exists: + /* + Model inputModel = new Model(); + Model outputModel = genericTestService.model(inputModel); + assertSame(inputModel, outputModel, "The inherited model method should return the same Model object."); + */ + } + + /** + * Test implementation of EventListener interface. + * Verifies that the class correctly implements the EventListener marker interface. + */ + @Test + void testEventListenerImplementation() { + assertTrue(genericTestService instanceof java.util.EventListener, + "GenericTestService should implement the EventListener interface."); + } +} diff --git a/microsphere-java-test/src/test/java/io/microsphere/test/service/TestServiceImplTest.java b/microsphere-java-test/src/test/java/io/microsphere/test/service/TestServiceImplTest.java new file mode 100644 index 000000000..b7fc3ecf8 --- /dev/null +++ b/microsphere-java-test/src/test/java/io/microsphere/test/service/TestServiceImplTest.java @@ -0,0 +1,75 @@ +package io.microsphere.test.service; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.context.ApplicationContext; +import org.springframework.core.env.Environment; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.mockito.Mockito.mock; + +/** + * Unit tests for the TestServiceImpl class. + */ +class TestServiceImplTest { + + private TestServiceImpl testService; + private ApplicationContext mockContext; + private Environment mockEnvironment; + + @BeforeEach + void setUp() { + // Mock dependencies + mockContext = mock(ApplicationContext.class); + mockEnvironment = mock(Environment.class); + + // Initialize the service with mocked dependencies + testService = new TestServiceImpl(mockEnvironment); + testService.context = mockContext; // Inject mocked ApplicationContext + } + + /** + * Test the echo method. + * Verifies that the method correctly prefixes the input message with "[ECHO] ". + */ + @Test + void testEcho() { + String input = "Hello, World!"; + String expectedOutput = "[ECHO] Hello, World!"; + String actualOutput = testService.echo(input); + assertEquals(expectedOutput, actualOutput, "The echo method should prefix the message with '[ECHO] '."); + } + + /** + * Test the close method. + * Verifies that the method does not throw any exceptions. + */ + @Test + void testClose() { + assertDoesNotThrow(() -> testService.close(), "The close method should not throw any exceptions."); + } + + /** + * Test constructor with Environment parameter. + * Verifies that the environment is properly injected. + */ + @Test + void testConstructorWithEnvironment() { + assertNotNull(testService.environment, "The environment should be injected via constructor."); + assertSame(mockEnvironment, testService.environment, "The injected environment should match the mocked instance."); + } + + /** + * Test default constructor. + * Verifies that the service can be instantiated without an Environment. + */ + @Test + void testDefaultConstructor() { + TestServiceImpl service = new TestServiceImpl(); + assertNull(service.environment, "The environment should be null when using the default constructor."); + } +} diff --git a/microsphere-jdk-tools/pom.xml b/microsphere-jdk-tools/pom.xml new file mode 100644 index 000000000..b0822a8de --- /dev/null +++ b/microsphere-jdk-tools/pom.xml @@ -0,0 +1,58 @@ + + + + io.github.microsphere-projects + microsphere-java-parent + ${revision} + ../microsphere-java-parent/pom.xml + + 4.0.0 + + io.github.microsphere-projects + microsphere-jdk-tools + ${revision} + jar + + Microsphere :: JDK :: Tools + Microsphere JDK Tools + + + + + + io.github.microsphere-projects + microsphere-java-core + ${revision} + + + + + org.junit.jupiter + junit-jupiter + test + + + + org.junit.jupiter + junit-jupiter-engine + test + + + + + org.mockito + mockito-core + test + + + + + ch.qos.logback + logback-classic + test + + + + \ No newline at end of file diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/Compiler.java b/microsphere-jdk-tools/src/main/java/io/microsphere/jdk/tools/compiler/Compiler.java similarity index 50% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/Compiler.java rename to microsphere-jdk-tools/src/main/java/io/microsphere/jdk/tools/compiler/Compiler.java index b8545abbc..09ab04336 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/Compiler.java +++ b/microsphere-jdk-tools/src/main/java/io/microsphere/jdk/tools/compiler/Compiler.java @@ -14,11 +14,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor; +package io.microsphere.jdk.tools.compiler; import io.microsphere.logging.Logger; import javax.annotation.processing.Processor; +import javax.tools.DiagnosticListener; import javax.tools.JavaCompiler; import javax.tools.JavaCompiler.CompilationTask; import javax.tools.JavaFileObject; @@ -26,24 +27,35 @@ import java.io.File; import java.io.IOException; import java.net.URL; -import java.util.LinkedHashSet; +import java.nio.charset.Charset; +import java.security.CodeSource; +import java.security.ProtectionDomain; import java.util.List; +import java.util.Locale; +import java.util.Objects; import java.util.Set; import static io.microsphere.collection.CollectionUtils.addAll; import static io.microsphere.collection.CollectionUtils.first; -import static io.microsphere.collection.ListUtils.newArrayList; +import static io.microsphere.collection.CollectionUtils.isEmpty; import static io.microsphere.collection.Lists.ofList; import static io.microsphere.collection.SetUtils.newLinkedHashSet; +import static io.microsphere.collection.Sets.ofSet; import static io.microsphere.constants.FileConstants.JAVA_EXTENSION; -import static io.microsphere.constants.ProtocolConstants.FILE_PROTOCOL; import static io.microsphere.constants.SymbolConstants.DOT_CHAR; import static io.microsphere.io.scanner.SimpleFileScanner.INSTANCE; import static io.microsphere.logging.LoggerFactory.getLogger; +import static io.microsphere.text.FormatUtils.format; +import static io.microsphere.util.ArrayUtils.ofArray; import static io.microsphere.util.ClassUtils.getTypeName; import static io.microsphere.util.StringUtils.substringBefore; import static java.io.File.separatorChar; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptySet; import static java.util.Collections.singleton; +import static java.util.Collections.unmodifiableList; +import static java.util.Collections.unmodifiableSet; +import static java.util.stream.Stream.of; import static javax.tools.StandardLocation.CLASS_OUTPUT; import static javax.tools.StandardLocation.SOURCE_OUTPUT; import static javax.tools.StandardLocation.SOURCE_PATH; @@ -59,136 +71,144 @@ public class Compiler { private static final Logger logger = getLogger(Compiler.class); + public static final String[] DEFAULT_OPTIONS = ofArray("-parameters", "-Xlint:unchecked", "-nowarn", "-Xlint:deprecation"); + private final Set sourcePaths; + private final File targetDirectory; + private final JavaCompiler javaCompiler; - private final StandardJavaFileManager javaFileManager; + private Set processors; + + private List options; + + private DiagnosticListener diagnosticListener; - private final Set processors = new LinkedHashSet<>(); + private Locale locale; - public Compiler() throws IOException { + private Charset charset; + + public Compiler() { this(defaultTargetDirectory()); } - public Compiler(File targetDirectory) throws IOException { + public Compiler(File targetDirectory) { this(defaultSourceDirectory(), targetDirectory); } - public Compiler(File defaultSourceDirectory, File targetDirectory) throws IOException { + public Compiler(File defaultSourceDirectory, File targetDirectory) { + options(DEFAULT_OPTIONS); this.sourcePaths = newLinkedHashSet(defaultSourceDirectory); + this.targetDirectory = targetDirectory; this.javaCompiler = getSystemJavaCompiler(); - this.javaFileManager = javaCompiler.getStandardFileManager(null, null, null); - this.javaFileManager.setLocation(SOURCE_PATH, sourcePaths); - this.javaFileManager.setLocation(CLASS_OUTPUT, singleton(targetDirectory)); - this.javaFileManager.setLocation(SOURCE_OUTPUT, singleton(targetDirectory)); } - static File defaultSourceDirectory() { - return detectSourcePath(Compiler.class); + public Compiler options(String... options) { + this.options = ofList(options); + return this; } - static File defaultRootDirectory() { - return detectRootDirectory(Compiler.class); + public Compiler sourcePaths(File... sourcePaths) { + addAll(this.sourcePaths, sourcePaths); + return this; } - static File defaultTargetDirectory() { - File dir = new File(defaultRootDirectory(), "target/generated-classes"); - dir.mkdirs(); - return dir; + public Compiler sourcePaths(Class... sourceClasses) { + for (Class sourceClass : sourceClasses) { + sourcePath(sourceClass); + } + return this; } - static File detectSourcePath(Class sourceClass) { - File rootDirectory = detectRootDirectory(sourceClass); - String javaSourceFileRelativePath = resolveJavaSourceFileRelativePath(sourceClass); - - Set sourceFiles = INSTANCE.scan(rootDirectory, true, - file -> file.getAbsolutePath().endsWith(javaSourceFileRelativePath)); - if (sourceFiles.isEmpty()) { - if (logger.isTraceEnabled()) { - logger.trace("The source files of class[name : '{}'] can't be found in the root directory[path :'{}']", - getTypeName(sourceClass), rootDirectory.getAbsolutePath()); - } - return null; + public Compiler sourcePath(Class sourceClass) { + File sourcePath = detectSourcePath(sourceClass); + if (sourcePath != null) { + return sourcePaths(sourcePath); } + return this; + } - File sourceFile = first(sourceFiles); - String javaSourceFilePath = sourceFile.getAbsolutePath(); - String javaSourcePath = substringBefore(javaSourceFilePath, javaSourceFileRelativePath); - File sourcePath = new File(javaSourcePath); + public Compiler processors(Processor... processors) { + this.processors = ofSet(processors); + return this; + } - if (logger.isTraceEnabled()) { - logger.trace("The source file[path : '{}] of class[name : '{}'] was found in the source directory[path :'{}']", - sourceFile.getAbsolutePath(), getTypeName(sourceClass), sourcePath.getAbsolutePath()); - } + public Compiler diagnosticListener(DiagnosticListener diagnosticListener) { + this.diagnosticListener = diagnosticListener; + return this; + } - return sourcePath.exists() ? sourcePath : null; + public Compiler locale(Locale locale) { + this.locale = locale; + return this; } - static File detectRootDirectory(Class sourceClass) { - File classPath = detectClassPath(sourceClass); - // classPath : "${rootDirectory}/target/classes" - File rootDirectory = classPath.getParentFile().getParentFile(); - if (logger.isTraceEnabled()) { - logger.trace("The root directory[path : '{}'] was found by the source class[name : '{}']", - rootDirectory.getAbsolutePath(), getTypeName(sourceClass)); - } - return rootDirectory; + public Compiler charset(Charset charset) { + this.charset = charset; + return this; } - static File detectClassPath(Class sourceClass) { - URL classFileURL = sourceClass.getProtectionDomain().getCodeSource().getLocation(); - if (FILE_PROTOCOL.equals(classFileURL.getProtocol())) { - return new File(classFileURL.getPath()); - } else { - throw new RuntimeException("No support"); - } + public boolean compile(Class... sourceClasses) throws IOException { + JavaCompiler javaCompiler = getJavaCompiler(); + StandardJavaFileManager javaFileManager = getJavaFileManager(); + CompilationTask task = javaCompiler.getTask(null, javaFileManager, + getDiagnosticListener(), getOptions(), null, getJavaFileObjects(javaFileManager, sourceClasses)); + task.setProcessors(this.getProcessors()); + return task.call(); } - static String resolveJavaSourceFileRelativePath(Class sourceClass) { - return sourceClass.getName().replace(DOT_CHAR, separatorChar).concat(JAVA_EXTENSION); + public JavaCompiler getJavaCompiler() { + return this.javaCompiler; } - public Compiler sourcePaths(File... sourcePaths) { - addAll(this.sourcePaths, sourcePaths); - return this; + public StandardJavaFileManager getJavaFileManager() throws IOException { + StandardJavaFileManager javaFileManager = getJavaCompiler().getStandardFileManager(getDiagnosticListener(), getLocale(), getCharset()); + javaFileManager.setLocation(SOURCE_PATH, this.sourcePaths); + javaFileManager.setLocation(CLASS_OUTPUT, singleton(this.targetDirectory)); + javaFileManager.setLocation(SOURCE_OUTPUT, singleton(this.targetDirectory)); + return javaFileManager; } - public Compiler sourcePaths(Iterable> sourceClasses) { - for (Class sourceClass : sourceClasses) { - sourcePath(sourceClass); - } - return this; + public DiagnosticListener getDiagnosticListener() { + return this.diagnosticListener; } - public Compiler sourcePath(Class sourceClass) { - File sourcePath = detectSourcePath(sourceClass); - if (sourcePath != null) { - return sourcePaths(sourcePath); - } - return this; + public Locale getLocale() { + return this.locale; } - public Compiler processors(Processor... processors) { - addAll(this.processors, processors); - return this; + public Charset getCharset() { + return this.charset; } - private Iterable getJavaFileObjects(Class... sourceClasses) { - int size = sourceClasses == null ? 0 : sourceClasses.length; - List javaSourceFiles = newArrayList(size); - for (int i = 0; i < size; i++) { - File javaSourceFile = searchJavaSourceFile(sourceClasses[i]); - if (javaSourceFile != null) { - javaSourceFiles.add(javaSourceFile); - } + public List getOptions() { + List options = this.options; + if (isEmpty(options)) { + return emptyList(); } - return javaFileManager.getJavaFileObjects(javaSourceFiles.toArray(new File[0])); + return unmodifiableList(options); + } + + public Set getProcessors() { + Set processors = this.processors; + if (processors == null) { + return emptySet(); + } + return unmodifiableSet(processors); + } + + private Iterable getJavaFileObjects(StandardJavaFileManager javaFileManager, Class... sourceClasses) { + File[] javaFiles = of(sourceClasses) + .map(this::searchJavaSourceFile) + .filter(Objects::nonNull) + .toArray(File[]::new); + return javaFileManager.getJavaFileObjects(javaFiles); } private File searchJavaSourceFile(Class sourceClass) { String javaSourceFilePath = resolveJavaSourceFileRelativePath(sourceClass); - for (File sourceDirectory : sourcePaths) { + for (File sourceDirectory : this.sourcePaths) { File javaSourceFile = new File(sourceDirectory, javaSourceFilePath); if (javaSourceFile.exists()) { return javaSourceFile; @@ -197,18 +217,63 @@ private File searchJavaSourceFile(Class sourceClass) { return null; } - public boolean compile(Class... sourceClasses) { - CompilationTask task = javaCompiler.getTask(null, this.javaFileManager, null, - ofList("-parameters", "-Xlint:unchecked", "-nowarn", "-Xlint:deprecation"), -// null, - null, getJavaFileObjects(sourceClasses)); - if (!processors.isEmpty()) { - task.setProcessors(processors); + static File defaultSourceDirectory() { + return detectSourcePath(Compiler.class); + } + + static File defaultRootDirectory() { + return detectRootDirectory(Compiler.class); + } + + static File defaultTargetDirectory() { + File dir = new File(defaultRootDirectory(), "target/generated-classes"); + dir.mkdirs(); + return dir; + } + + public static File detectSourcePath(Class sourceClass) { + File rootDirectory = detectRootDirectory(sourceClass); + String javaSourceFileRelativePath = resolveJavaSourceFileRelativePath(sourceClass); + + Set sourceFiles = INSTANCE.scan(rootDirectory, true, + file -> file.getAbsolutePath().endsWith(javaSourceFileRelativePath)); + + File sourceFile = first(sourceFiles); + if (sourceFile == null) { + logger.trace("The source files of {} can't be found in the root directory[path :'{}']", sourceClass, rootDirectory); + return null; } - return task.call(); + + String javaSourceFilePath = sourceFile.getAbsolutePath(); + String javaSourcePath = substringBefore(javaSourceFilePath, javaSourceFileRelativePath); + File sourcePath = new File(javaSourcePath); + + logger.trace("The source file[path : '{}] of {} was found in the source directory[path :'{}']", sourceFile, sourceClass, sourcePath); + + return sourcePath; } - public JavaCompiler getJavaCompiler() { - return javaCompiler; + public static File detectRootDirectory(Class sourceClass) { + File classPath = detectClassPath(sourceClass); + // classPath : "${rootDirectory}/target/classes" + File rootDirectory = classPath.getParentFile().getParentFile(); + logger.trace("The root directory[path : '{}'] was found by the source class[name : '{}']", + rootDirectory.getAbsolutePath(), getTypeName(sourceClass)); + return rootDirectory; + } + + public static File detectClassPath(Class sourceClass) { + ProtectionDomain protectionDomain = sourceClass.getProtectionDomain(); + CodeSource codeSource = protectionDomain.getCodeSource(); + if (codeSource != null) { + URL location = codeSource.getLocation(); + return new File(location.getPath()); + } + String message = format("The source {} is based on the file system, the class path can't be detected.", sourceClass); + throw new UnsupportedOperationException(message); + } + + public static String resolveJavaSourceFileRelativePath(Class sourceClass) { + return sourceClass.getName().replace(DOT_CHAR, separatorChar).concat(JAVA_EXTENSION); } -} +} \ No newline at end of file diff --git a/microsphere-jdk-tools/src/test/java/io/microsphere/jdk/tools/compiler/CompilerTest.java b/microsphere-jdk-tools/src/test/java/io/microsphere/jdk/tools/compiler/CompilerTest.java new file mode 100644 index 000000000..78023fafc --- /dev/null +++ b/microsphere-jdk-tools/src/test/java/io/microsphere/jdk/tools/compiler/CompilerTest.java @@ -0,0 +1,188 @@ +package io.microsphere.jdk.tools.compiler; + +import org.junit.jupiter.api.Test; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.Processor; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.element.TypeElement; +import java.io.File; +import java.io.IOException; +import java.util.Set; + +import static io.microsphere.jdk.tools.compiler.Compiler.defaultRootDirectory; +import static io.microsphere.jdk.tools.compiler.Compiler.defaultSourceDirectory; +import static io.microsphere.jdk.tools.compiler.Compiler.defaultTargetDirectory; +import static io.microsphere.jdk.tools.compiler.Compiler.detectClassPath; +import static io.microsphere.jdk.tools.compiler.Compiler.detectRootDirectory; +import static io.microsphere.jdk.tools.compiler.Compiler.detectSourcePath; +import static io.microsphere.jdk.tools.compiler.Compiler.resolveJavaSourceFileRelativePath; +import static java.io.File.separatorChar; +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.util.Locale.getDefault; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Unit tests for the Compiler class + * + * @see Compiler + */ +class CompilerTest { + + @Test + void testDefaultConstructor() { + // Test default constructor which uses default target directory + Compiler compiler = new Compiler(); + + assertNotNull(compiler, "Compiler should be instantiated successfully"); + assertNotNull(compiler.getJavaCompiler(), "JavaCompiler should be initialized"); + } + + @Test + void testTargetDirectoryConstructor() { + File targetDir = new File("target/test-classes"); + targetDir.mkdirs(); // Ensure directory exists + + Compiler compiler = new Compiler(targetDir); + + assertNotNull(compiler, "Compiler should be instantiated successfully with target directory"); + assertNotNull(compiler.getJavaCompiler(), "JavaCompiler should be initialized"); + } + + @Test + void testSourceAndTargetDirectoryConstructor() { + File sourceDir = new File("src/test/java"); + File targetDir = new File("target/test-classes"); + targetDir.mkdirs(); // Ensure target directory exists + + Compiler compiler = new Compiler(sourceDir, targetDir); + + assertNotNull(compiler, "Compiler should be instantiated successfully with source and target directories"); + assertNotNull(compiler.getJavaCompiler(), "JavaCompiler should be initialized"); + } + + @Test + void testDefaultDirectories() { + // Test the static methods that determine default directories + File defaultSourceDir = defaultSourceDirectory(); + File defaultTargetDir = defaultTargetDirectory(); + File defaultRootDir = defaultRootDirectory(); + + // Root directory should exist (it's derived from the Compiler class location) + assertNotNull(defaultSourceDir, "Default source directory should not be null"); + assertNotNull(defaultRootDir, "Default root directory should not be null"); + assertTrue(defaultRootDir.exists(), "Default root directory should exist"); + + // Target directory should be created + assertNotNull(defaultTargetDir, "Default target directory should not be null"); + } + + @Test + void testDetectClassPath() { + File classPath = detectClassPath(Compiler.class); + + assertNotNull(classPath, "Detected class path should not be null"); + assertTrue(classPath.exists(), "Detected class path should exist"); + + assertThrows(UnsupportedOperationException.class, () -> detectClassPath(String.class)); + } + + @Test + void testResolveJavaSourceFileRelativePath() { + String expectedPath = Compiler.class.getName() + .replace('.', separatorChar) + .concat(".java"); + String actualPath = resolveJavaSourceFileRelativePath(Compiler.class); + + assertEquals(expectedPath, actualPath, + "Resolved Java source file relative path should match expected format"); + } + + @Test + void testSourcePathsMethod() { + File targetDir = new File("target/test-classes"); + targetDir.mkdirs(); + + Compiler compiler = new Compiler(targetDir); + + File testSourcePath = new File("src/main/java"); + Compiler result = compiler.sourcePaths(testSourcePath); + + // Verify method chaining returns the same instance + assertSame(compiler, result, "sourcePaths method should return the same instance for chaining"); + + result = compiler.sourcePaths(Compiler.class, Test.class); + assertSame(compiler, result, "sourcePaths method should return the same instance for chaining"); + } + + @Test + void testProcessorsMethod() { + File targetDir = new File("target/test-classes"); + targetDir.mkdirs(); + + Compiler compiler = new Compiler(targetDir); + Processor processor = new AbstractProcessor() { + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + return false; + } + }; + + Compiler result = compiler.processors(processor); + + // Verify method chaining returns the same instance + assertSame(compiler, result, "processors method should return the same instance for chaining"); + } + + @Test + void testCompile() throws IOException { + Compiler compiler = new Compiler(); + + // This would normally attempt compilation, but with mocked compiler it's safe to call + boolean result = compiler.compile(Compiler.class, Test.class); + + // For this test, we're primarily verifying the setup doesn't fail + // Actual compilation success depends on the mock setup + assertTrue(result, "Test setup completed without exceptions"); + + compiler.options() + .processors(new AbstractProcessor() { + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + return false; + } + }) + .diagnosticListener(diagnostic -> { + }) + .locale(getDefault()) + .charset(UTF_8) + ; + + result = compiler.compile(Compiler.class); + + assertTrue(result, "Test setup completed without exceptions"); + } + + @Test + void testDetectRootDirectory() { + File rootDir = detectRootDirectory(Compiler.class); + + assertNotNull(rootDir, "Root directory should not be null"); + assertTrue(rootDir.exists(), "Root directory should exist"); + } + + @Test + void testDetectSourcePath() { + // This might be null if source path cannot be detected in test environment + // but the method should not throw exceptions + assertNotNull(detectSourcePath(Compiler.class), "Should be able to call detectSourcePath without errors"); + assertNotNull(detectSourcePath(CompilerTest.class), "Should be able to call detectSourcePath without errors"); + assertNull(detectSourcePath(Test.class), "Should be able to call detectSourcePath without errors"); + } +} diff --git a/microsphere-jdk-tools/src/test/resources/logback-test.xml b/microsphere-jdk-tools/src/test/resources/logback-test.xml new file mode 100644 index 000000000..e3375b74c --- /dev/null +++ b/microsphere-jdk-tools/src/test/resources/logback-test.xml @@ -0,0 +1,15 @@ + + + + + + + ${ENCODER_PATTERN} + + + + + + + + \ No newline at end of file diff --git a/microsphere-lang-model/pom.xml b/microsphere-lang-model/pom.xml new file mode 100644 index 000000000..101084931 --- /dev/null +++ b/microsphere-lang-model/pom.xml @@ -0,0 +1,95 @@ + + + + io.github.microsphere-projects + microsphere-java-parent + ${revision} + ../microsphere-java-parent/pom.xml + + 4.0.0 + + io.github.microsphere-projects + microsphere-lang-model + ${revision} + jar + + Microsphere :: Java :: Language Model + Microsphere Language Model + + + + + + io.github.microsphere-projects + microsphere-java-core + ${revision} + + + + + org.junit.jupiter + junit-jupiter + test + + + + org.junit.jupiter + junit-jupiter-engine + test + + + + + io.github.microsphere-projects + microsphere-jdk-tools + ${revision} + test + + + + + io.github.microsphere-projects + microsphere-java-test + ${revision} + test + + + + + ch.qos.logback + logback-classic + test + + + + + javax.ws.rs + javax.ws.rs-api + test + + + + + javax.xml.ws + jaxws-api + test + + + + + org.springframework + spring-context + test + + + + org.springframework + spring-web + test + + + + + \ No newline at end of file diff --git a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/model/element/StringAnnotationValue.java b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/element/StringAnnotationValue.java similarity index 96% rename from microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/model/element/StringAnnotationValue.java rename to microsphere-lang-model/src/main/java/io/microsphere/lang/model/element/StringAnnotationValue.java index 42a583f75..ba92765e6 100644 --- a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/model/element/StringAnnotationValue.java +++ b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/element/StringAnnotationValue.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package io.microsphere.annotation.processor.model.element; +package io.microsphere.lang.model.element; import io.microsphere.annotation.Immutable; diff --git a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/model/util/AnnotatedElementJSONElementVisitor.java b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/AnnotatedElementJSONElementVisitor.java similarity index 90% rename from microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/model/util/AnnotatedElementJSONElementVisitor.java rename to microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/AnnotatedElementJSONElementVisitor.java index b5c76b0b1..e6df266ec 100644 --- a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/model/util/AnnotatedElementJSONElementVisitor.java +++ b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/AnnotatedElementJSONElementVisitor.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package io.microsphere.annotation.processor.model.util; +package io.microsphere.lang.model.util; import io.microsphere.annotation.Nonnull; @@ -29,16 +29,16 @@ import java.lang.annotation.ElementType; import java.lang.reflect.AnnotatedElement; -import static io.microsphere.annotation.processor.util.AnnotationUtils.getElementTypes; -import static io.microsphere.annotation.processor.util.ElementUtils.matchesElementType; -import static io.microsphere.annotation.processor.util.TypeUtils.getDeclaredType; +import static io.microsphere.lang.model.util.AnnotationUtils.getElementTypes; +import static io.microsphere.lang.model.util.ElementUtils.matchesElementType; +import static io.microsphere.lang.model.util.TypeUtils.getDeclaredType; import static io.microsphere.util.Assert.assertNotNull; /** * An abstract implementation of {@link ElementVisitor} that generates JSON content for elements * annotated with a specific annotation. * - *

    This class extends {@link JSONElementVisitor}, providing functionality to filter and process + *

    This class extends {@link io.microsphere.lang.model.util.JSONElementVisitor}, providing functionality to filter and process * only those elements that are annotated with the specified annotation. It leverages the annotation * processing environment to gather information about the annotated elements and constructs JSON * representations accordingly.

    @@ -79,7 +79,7 @@ * type elements annotated with a custom annotation and generates JSON output for them.

    * * @author Mercy - * @see JSONElementVisitor + * @see io.microsphere.lang.model.util.JSONElementVisitor * @see AnnotatedElement * @see Annotation * @see ElementType @@ -124,5 +124,4 @@ public final String getAnnotationClassName() { protected boolean supports(Element e) { return matchesElementType(e, this.elementTypes); } - } diff --git a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/AnnotationUtils.java b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/AnnotationUtils.java similarity index 98% rename from microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/AnnotationUtils.java rename to microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/AnnotationUtils.java index 4df0bdfc6..ea4859b76 100644 --- a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/AnnotationUtils.java +++ b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/AnnotationUtils.java @@ -14,12 +14,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor.util; +package io.microsphere.lang.model.util; import io.microsphere.annotation.Immutable; import io.microsphere.annotation.Nonnull; import io.microsphere.annotation.Nullable; -import io.microsphere.annotation.processor.model.util.ResolvableAnnotationValueVisitor; import io.microsphere.util.Utils; import javax.annotation.processing.ProcessingEnvironment; @@ -43,20 +42,21 @@ import java.util.Objects; import java.util.function.Predicate; -import static io.microsphere.annotation.processor.util.MethodUtils.findDeclaredMethods; -import static io.microsphere.annotation.processor.util.MethodUtils.getDeclaredMethods; -import static io.microsphere.annotation.processor.util.MethodUtils.getMethodName; -import static io.microsphere.annotation.processor.util.TypeUtils.getAllTypeElements; -import static io.microsphere.annotation.processor.util.TypeUtils.getTypeElement; -import static io.microsphere.annotation.processor.util.TypeUtils.isSameType; -import static io.microsphere.annotation.processor.util.TypeUtils.ofTypeElement; import static io.microsphere.collection.CollectionUtils.isEmpty; import static io.microsphere.collection.CollectionUtils.size; +import static io.microsphere.collection.ListUtils.first; import static io.microsphere.collection.MapUtils.immutableEntry; import static io.microsphere.collection.MapUtils.isEmpty; import static io.microsphere.collection.MapUtils.newFixedLinkedHashMap; import static io.microsphere.lang.function.Predicates.EMPTY_PREDICATE_ARRAY; import static io.microsphere.lang.function.Streams.filterAll; +import static io.microsphere.lang.model.util.MethodUtils.findDeclaredMethods; +import static io.microsphere.lang.model.util.MethodUtils.getDeclaredMethods; +import static io.microsphere.lang.model.util.MethodUtils.getMethodName; +import static io.microsphere.lang.model.util.TypeUtils.getAllTypeElements; +import static io.microsphere.lang.model.util.TypeUtils.getTypeElement; +import static io.microsphere.lang.model.util.TypeUtils.isSameType; +import static io.microsphere.lang.model.util.TypeUtils.ofTypeElement; import static io.microsphere.util.ArrayUtils.isNotEmpty; import static io.microsphere.util.StringUtils.isBlank; import static java.util.Collections.emptyList; @@ -170,7 +170,7 @@ static AnnotationMirror getAnnotation(AnnotatedConstruct annotatedConstruct, Cha return null; } List annotations = getAnnotations(annotatedConstruct, annotationClassName); - return annotations.isEmpty() ? null : annotations.get(0); + return first(annotations); } /** @@ -607,7 +607,7 @@ static AnnotationMirror findAnnotation(Element element, CharSequence annotationC return null; } List annotations = findAllAnnotations(element, annotation -> matchesAnnotationTypeName(annotation, annotationClassName)); - return isEmpty(annotations) ? null : annotations.get(0); + return first(annotations); } /** @@ -1142,7 +1142,10 @@ static boolean matchesAttributeValue(AnnotationValue annotationValue, Object att * {@code false} otherwise */ static boolean matchesDefaultAttributeValue(ExecutableElement attributeMethod, AnnotationValue annotationValue) { - return attributeMethod != null && matchesAttributeValue(attributeMethod.getDefaultValue(), annotationValue); + if (attributeMethod == null) { + return false; + } + return matchesAttributeValue(attributeMethod.getDefaultValue(), annotationValue); } /** @@ -1582,17 +1585,18 @@ static Entry getElementValue(AnnotationMirro if (withDefault && annotationValue == null) { // not found if the default value is required DeclaredType annotationType = annotation.getAnnotationType(); - List attributeMethods = findDeclaredMethods(annotationType, method -> !elementValues.containsKey(method)); - int size = attributeMethods.size(); - for (int i = 0; i < size; i++) { - attributeMethod = attributeMethods.get(i); - if (matchesAttributeMethod(attributeMethod, attributeName)) { - annotationValue = attributeMethod.getDefaultValue(); - break; - } + List attributeMethods = findDeclaredMethods(annotationType, method -> + !elementValues.containsKey(method) && matchesAttributeMethod(method, attributeName)); + attributeMethod = first(attributeMethods); + if (attributeMethod != null) { + annotationValue = attributeMethod.getDefaultValue(); } } + if (annotationValue == null) { + return null; + } + return immutableEntry(attributeMethod, annotationValue); } diff --git a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/ClassUtils.java b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/ClassUtils.java similarity index 97% rename from microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/ClassUtils.java rename to microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/ClassUtils.java index 77988604c..7b83b0c99 100644 --- a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/ClassUtils.java +++ b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/ClassUtils.java @@ -15,15 +15,15 @@ * limitations under the License. */ -package io.microsphere.annotation.processor.util; +package io.microsphere.lang.model.util; import io.microsphere.util.Utils; import javax.lang.model.type.TypeMirror; -import static io.microsphere.annotation.processor.util.TypeUtils.ofTypeElement; import static io.microsphere.constants.SymbolConstants.DOLLAR_CHAR; import static io.microsphere.constants.SymbolConstants.DOT_CHAR; +import static io.microsphere.lang.model.util.TypeUtils.ofTypeElement; import static io.microsphere.util.ClassLoaderUtils.getClassLoader; import static io.microsphere.util.ClassLoaderUtils.resolveClass; diff --git a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/ConstructorUtils.java b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/ConstructorUtils.java similarity index 97% rename from microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/ConstructorUtils.java rename to microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/ConstructorUtils.java index e19f43845..c864c1c7d 100644 --- a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/ConstructorUtils.java +++ b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/ConstructorUtils.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package io.microsphere.annotation.processor.util; +package io.microsphere.lang.model.util; import io.microsphere.annotation.Immutable; import io.microsphere.annotation.Nonnull; @@ -32,12 +32,12 @@ import java.util.List; import java.util.function.Predicate; -import static io.microsphere.annotation.processor.util.ElementUtils.filterElements; -import static io.microsphere.annotation.processor.util.ElementUtils.matchParameterTypes; -import static io.microsphere.annotation.processor.util.MemberUtils.getDeclaredMembers; import static io.microsphere.collection.CollectionUtils.isEmpty; import static io.microsphere.collection.ListUtils.first; import static io.microsphere.lang.function.Predicates.EMPTY_PREDICATE_ARRAY; +import static io.microsphere.lang.model.util.ElementUtils.filterElements; +import static io.microsphere.lang.model.util.ElementUtils.matchParameterTypes; +import static io.microsphere.lang.model.util.MemberUtils.getDeclaredMembers; import static java.util.Collections.emptyList; import static javax.lang.model.util.ElementFilter.constructorsIn; diff --git a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/ElementUtils.java b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/ElementUtils.java similarity index 99% rename from microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/ElementUtils.java rename to microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/ElementUtils.java index a6d7db851..f24373a19 100644 --- a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/ElementUtils.java +++ b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/ElementUtils.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package io.microsphere.annotation.processor.util; +package io.microsphere.lang.model.util; import io.microsphere.annotation.Immutable; import io.microsphere.annotation.Nonnull; @@ -32,9 +32,9 @@ import java.util.Set; import java.util.function.Predicate; -import static io.microsphere.annotation.processor.util.TypeUtils.isSameType; import static io.microsphere.collection.CollectionUtils.isEmpty; import static io.microsphere.lang.function.Predicates.and; +import static io.microsphere.lang.model.util.TypeUtils.isSameType; import static io.microsphere.reflect.TypeUtils.getTypeNames; import static io.microsphere.util.ArrayUtils.isNotEmpty; import static io.microsphere.util.ArrayUtils.length; diff --git a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/ExecutableElementComparator.java b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/ExecutableElementComparator.java similarity index 98% rename from microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/ExecutableElementComparator.java rename to microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/ExecutableElementComparator.java index c7e561224..ead937db0 100644 --- a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/ExecutableElementComparator.java +++ b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/ExecutableElementComparator.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor.util; +package io.microsphere.lang.model.util; import io.microsphere.util.CharSequenceComparator; diff --git a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/FieldUtils.java b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/FieldUtils.java similarity index 98% rename from microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/FieldUtils.java rename to microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/FieldUtils.java index f1c195fd9..b14dd47a1 100644 --- a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/FieldUtils.java +++ b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/FieldUtils.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor.util; +package io.microsphere.lang.model.util; import io.microsphere.annotation.Immutable; import io.microsphere.annotation.Nonnull; @@ -29,14 +29,14 @@ import java.util.List; import java.util.function.Predicate; -import static io.microsphere.annotation.processor.util.ElementUtils.filterElements; -import static io.microsphere.annotation.processor.util.ElementUtils.hasModifiers; -import static io.microsphere.annotation.processor.util.ElementUtils.matchesElementKind; -import static io.microsphere.annotation.processor.util.MemberUtils.getDeclaredMembers; -import static io.microsphere.annotation.processor.util.TypeUtils.isEnumType; import static io.microsphere.collection.CollectionUtils.isEmpty; import static io.microsphere.lang.function.Predicates.EMPTY_PREDICATE_ARRAY; import static io.microsphere.lang.function.Streams.filterFirst; +import static io.microsphere.lang.model.util.ElementUtils.filterElements; +import static io.microsphere.lang.model.util.ElementUtils.hasModifiers; +import static io.microsphere.lang.model.util.ElementUtils.matchesElementKind; +import static io.microsphere.lang.model.util.MemberUtils.getDeclaredMembers; +import static io.microsphere.lang.model.util.TypeUtils.isEnumType; import static java.util.Collections.emptyList; import static javax.lang.model.element.ElementKind.ENUM_CONSTANT; import static javax.lang.model.element.ElementKind.FIELD; diff --git a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/model/util/JSONAnnotationValueVisitor.java b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/JSONAnnotationValueVisitor.java similarity index 96% rename from microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/model/util/JSONAnnotationValueVisitor.java rename to microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/JSONAnnotationValueVisitor.java index 327c954b0..01b074447 100644 --- a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/model/util/JSONAnnotationValueVisitor.java +++ b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/JSONAnnotationValueVisitor.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package io.microsphere.annotation.processor.model.util; +package io.microsphere.lang.model.util; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationValue; @@ -28,9 +28,6 @@ import java.util.Map; import java.util.Map.Entry; -import static io.microsphere.annotation.processor.util.AnnotationUtils.getAttributeName; -import static io.microsphere.annotation.processor.util.AnnotationUtils.getElementValues; -import static io.microsphere.annotation.processor.util.TypeUtils.getTypeName; import static io.microsphere.constants.SymbolConstants.COMMA_CHAR; import static io.microsphere.constants.SymbolConstants.LEFT_CURLY_BRACE_CHAR; import static io.microsphere.constants.SymbolConstants.LEFT_SQUARE_BRACKET_CHAR; @@ -38,6 +35,9 @@ import static io.microsphere.constants.SymbolConstants.RIGHT_SQUARE_BRACKET_CHAR; import static io.microsphere.json.JSONUtils.append; import static io.microsphere.json.JSONUtils.appendName; +import static io.microsphere.lang.model.util.AnnotationUtils.getAttributeName; +import static io.microsphere.lang.model.util.AnnotationUtils.getElementValues; +import static io.microsphere.lang.model.util.TypeUtils.getTypeName; /** * A visitor implementation for converting {@link AnnotationValue} objects into JSON-formatted strings. @@ -78,7 +78,6 @@ public JSONAnnotationValueVisitor(StringBuilder jsonBuilder) { this.jsonBuilder = jsonBuilder; } - @Override public StringBuilder visitBoolean(boolean value, ExecutableElement attributeMethod) { append(jsonBuilder, getAttributeName(attributeMethod), value); diff --git a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/model/util/JSONElementVisitor.java b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/JSONElementVisitor.java similarity index 90% rename from microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/model/util/JSONElementVisitor.java rename to microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/JSONElementVisitor.java index 99856edb3..416eafce3 100644 --- a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/model/util/JSONElementVisitor.java +++ b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/JSONElementVisitor.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package io.microsphere.annotation.processor.model.util; +package io.microsphere.lang.model.util; import javax.lang.model.element.Element; import javax.lang.model.element.ElementVisitor; @@ -62,26 +62,36 @@ public JSONElementVisitor() { @Override public final Boolean visitPackage(PackageElement e, StringBuilder jsonBuilder) { - return supportsPackage(e) && doVisitPackage(e, jsonBuilder); + if (!supportsPackage(e)) { + return false; + } + return doVisitPackage(e, jsonBuilder); } @Override public final Boolean visitVariable(VariableElement e, StringBuilder stringBuilder) { - return supportsVariable(e) && super.visitVariable(e, stringBuilder); + if (!supportsVariable(e)) { + return false; + } + return super.visitVariable(e, stringBuilder); } @Override public final Boolean visitExecutable(ExecutableElement e, StringBuilder jsonBuilder) { - return supportsExecutable(e) && super.visitExecutable(e, jsonBuilder); + if (!supportsExecutable(e)) { + return false; + } + return super.visitExecutable(e, jsonBuilder); } @Override public final Boolean visitType(TypeElement e, StringBuilder jsonBuilder) { - boolean appended = false; - if (supportsType(e) && super.visitType(e, jsonBuilder)) { - appended = true; + if (!supportsType(e)) { + return false; } + boolean appended = super.visitType(e, jsonBuilder); + // The declared members of the type element if (visitMembers(e.getEnclosedElements(), jsonBuilder)) { appended = true; @@ -92,21 +102,10 @@ public final Boolean visitType(TypeElement e, StringBuilder jsonBuilder) { @Override public final Boolean visitTypeParameter(TypeParameterElement e, StringBuilder jsonBuilder) { - if (!supports(e)) { - return FALSE; + if (!supportsTypeParameter(e)) { + return false; } - - boolean appended = false; - if (supportsTypeParameter(e) && doVisitTypeParameter(e, jsonBuilder)) { - appended = true; - } - - // The declared members of the type element - if (visitMembers(e.getEnclosedElements(), jsonBuilder)) { - appended = true; - } - - return appended; + return doVisitTypeParameter(e, jsonBuilder); } protected boolean visitMembers(List members, StringBuilder jsonBuilder) { @@ -218,4 +217,4 @@ protected boolean doVisitPackage(PackageElement e, StringBuilder jsonBuilder) { protected boolean doVisitTypeParameter(TypeParameterElement e, StringBuilder jsonBuilder) { return super.visitTypeParameter(e, jsonBuilder); } -} +} \ No newline at end of file diff --git a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/LoggerUtils.java b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/LoggerUtils.java similarity index 93% rename from microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/LoggerUtils.java rename to microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/LoggerUtils.java index 17b69dbeb..4fed09a7f 100644 --- a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/LoggerUtils.java +++ b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/LoggerUtils.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor.util; +package io.microsphere.lang.model.util; import io.microsphere.logging.Logger; @@ -30,7 +30,7 @@ */ public interface LoggerUtils extends Utils { - Logger LOGGER = getLogger("microsphere-annotation-processor"); + Logger LOGGER = getLogger("microsphere-lang-model"); static void trace(String format, Object... args) { LOGGER.trace(format, args); diff --git a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/MemberUtils.java b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/MemberUtils.java similarity index 98% rename from microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/MemberUtils.java rename to microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/MemberUtils.java index 46c1d9270..77f027a4f 100644 --- a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/MemberUtils.java +++ b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/MemberUtils.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor.util; +package io.microsphere.lang.model.util; import io.microsphere.annotation.Immutable; import io.microsphere.annotation.Nonnull; @@ -27,10 +27,10 @@ import java.util.List; import java.util.function.Predicate; -import static io.microsphere.annotation.processor.util.ElementUtils.filterElements; -import static io.microsphere.annotation.processor.util.TypeUtils.getAllDeclaredTypes; -import static io.microsphere.annotation.processor.util.TypeUtils.ofTypeElement; import static io.microsphere.lang.function.Predicates.EMPTY_PREDICATE_ARRAY; +import static io.microsphere.lang.model.util.ElementUtils.filterElements; +import static io.microsphere.lang.model.util.TypeUtils.getAllDeclaredTypes; +import static io.microsphere.lang.model.util.TypeUtils.ofTypeElement; import static java.util.Collections.emptyList; import static java.util.stream.Collectors.toList; diff --git a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/MessagerUtils.java b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/MessagerUtils.java similarity index 97% rename from microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/MessagerUtils.java rename to microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/MessagerUtils.java index 7668c478d..63ad95180 100644 --- a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/MessagerUtils.java +++ b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/MessagerUtils.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package io.microsphere.annotation.processor.util; +package io.microsphere.lang.model.util; import io.microsphere.util.Utils; @@ -23,10 +23,10 @@ import javax.annotation.processing.ProcessingEnvironment; import javax.tools.Diagnostic.Kind; -import static io.microsphere.annotation.processor.util.LoggerUtils.debug; -import static io.microsphere.annotation.processor.util.LoggerUtils.error; -import static io.microsphere.annotation.processor.util.LoggerUtils.info; -import static io.microsphere.annotation.processor.util.LoggerUtils.warn; +import static io.microsphere.lang.model.util.LoggerUtils.debug; +import static io.microsphere.lang.model.util.LoggerUtils.error; +import static io.microsphere.lang.model.util.LoggerUtils.info; +import static io.microsphere.lang.model.util.LoggerUtils.warn; import static io.microsphere.text.FormatUtils.format; import static javax.tools.Diagnostic.Kind.ERROR; import static javax.tools.Diagnostic.Kind.MANDATORY_WARNING; diff --git a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/MethodUtils.java b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/MethodUtils.java similarity index 98% rename from microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/MethodUtils.java rename to microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/MethodUtils.java index 510f73f59..de250a897 100644 --- a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/MethodUtils.java +++ b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/MethodUtils.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor.util; +package io.microsphere.lang.model.util; import io.microsphere.annotation.Immutable; @@ -34,17 +34,18 @@ import java.util.Objects; import java.util.function.Predicate; -import static io.microsphere.annotation.processor.util.ElementUtils.filterElements; -import static io.microsphere.annotation.processor.util.ElementUtils.isPublicNonStatic; -import static io.microsphere.annotation.processor.util.ElementUtils.matchParameterTypeNames; -import static io.microsphere.annotation.processor.util.ElementUtils.matchParameterTypes; -import static io.microsphere.annotation.processor.util.MemberUtils.getDeclaredMembers; -import static io.microsphere.annotation.processor.util.TypeUtils.isSameType; -import static io.microsphere.annotation.processor.util.TypeUtils.ofDeclaredType; import static io.microsphere.collection.CollectionUtils.isEmpty; +import static io.microsphere.collection.ListUtils.first; import static io.microsphere.lang.function.Predicates.EMPTY_PREDICATE_ARRAY; import static io.microsphere.lang.function.Predicates.and; import static io.microsphere.lang.function.Streams.filterFirst; +import static io.microsphere.lang.model.util.ElementUtils.filterElements; +import static io.microsphere.lang.model.util.ElementUtils.isPublicNonStatic; +import static io.microsphere.lang.model.util.ElementUtils.matchParameterTypeNames; +import static io.microsphere.lang.model.util.ElementUtils.matchParameterTypes; +import static io.microsphere.lang.model.util.MemberUtils.getDeclaredMembers; +import static io.microsphere.lang.model.util.TypeUtils.isSameType; +import static io.microsphere.lang.model.util.TypeUtils.ofDeclaredType; import static io.microsphere.util.ArrayUtils.EMPTY_STRING_ARRAY; import static io.microsphere.util.ArrayUtils.EMPTY_TYPE_ARRAY; import static io.microsphere.util.ArrayUtils.isNotEmpty; @@ -666,7 +667,7 @@ static ExecutableElement findMethod(TypeMirror type, String methodName, Type... return null; } List allDeclaredMethods = findAllDeclaredMethods(type, method -> matches(method, methodName, parameterTypes)); - return allDeclaredMethods.isEmpty() ? null : allDeclaredMethods.get(0); + return first(allDeclaredMethods); } /** @@ -730,7 +731,7 @@ static ExecutableElement findMethod(TypeMirror type, String methodName, CharSequ return null; } List allDeclaredMethods = findAllDeclaredMethods(type, method -> matches(method, methodName, parameterTypeNames)); - return allDeclaredMethods.isEmpty() ? null : allDeclaredMethods.get(0); + return first(allDeclaredMethods); } /** diff --git a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/model/util/ResolvableAnnotationValueVisitor.java b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/ResolvableAnnotationValueVisitor.java similarity index 95% rename from microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/model/util/ResolvableAnnotationValueVisitor.java rename to microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/ResolvableAnnotationValueVisitor.java index 888c2f7aa..86bce41b5 100644 --- a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/model/util/ResolvableAnnotationValueVisitor.java +++ b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/ResolvableAnnotationValueVisitor.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package io.microsphere.annotation.processor.model.util; +package io.microsphere.lang.model.util; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationValue; @@ -30,10 +30,10 @@ import java.util.Map; import java.util.Map.Entry; -import static io.microsphere.annotation.processor.util.AnnotationUtils.getAttributeName; -import static io.microsphere.annotation.processor.util.AnnotationUtils.getElementValues; -import static io.microsphere.annotation.processor.util.ClassUtils.loadClass; import static io.microsphere.collection.MapUtils.newFixedLinkedHashMap; +import static io.microsphere.lang.model.util.AnnotationUtils.getAttributeName; +import static io.microsphere.lang.model.util.AnnotationUtils.getElementValues; +import static io.microsphere.lang.model.util.ClassUtils.loadClass; import static io.microsphere.reflect.MethodUtils.findMethod; import static io.microsphere.reflect.MethodUtils.invokeStaticMethod; import static io.microsphere.util.ArrayUtils.newArray; diff --git a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/TypeUtils.java b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/TypeUtils.java similarity index 99% rename from microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/TypeUtils.java rename to microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/TypeUtils.java index 829ed464c..1da76f704 100644 --- a/microsphere-annotation-processor/src/main/java/io/microsphere/annotation/processor/util/TypeUtils.java +++ b/microsphere-lang-model/src/main/java/io/microsphere/lang/model/util/TypeUtils.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor.util; +package io.microsphere.lang.model.util; import io.microsphere.annotation.Immutable; import io.microsphere.annotation.Nonnull; @@ -579,7 +579,10 @@ static boolean isTypeElement(Element element) { */ static boolean isTypeElement(TypeMirror type) { DeclaredType declaredType = ofDeclaredType(type); - return declaredType != null && isTypeElement(declaredType.asElement()); + if (declaredType == null) { + return false; + } + return isTypeElement(declaredType.asElement()); } /** diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/element/StringAnnotationValueTest.java b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/element/StringAnnotationValueTest.java similarity index 91% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/element/StringAnnotationValueTest.java rename to microsphere-lang-model/src/test/java/io/microsphere/lang/model/element/StringAnnotationValueTest.java index 6e96fb50a..df77ef12c 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/element/StringAnnotationValueTest.java +++ b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/element/StringAnnotationValueTest.java @@ -15,10 +15,10 @@ * limitations under the License. */ -package io.microsphere.annotation.processor.model.element; +package io.microsphere.lang.model.element; -import io.microsphere.annotation.processor.model.util.ResolvableAnnotationValueVisitor; +import io.microsphere.lang.model.util.ResolvableAnnotationValueVisitor; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/AnnotatedElementJSONElementVisitorTest.java b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/AnnotatedElementJSONElementVisitorTest.java new file mode 100644 index 000000000..3dd0cc74c --- /dev/null +++ b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/AnnotatedElementJSONElementVisitorTest.java @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.microsphere.lang.model.util; + + +import org.junit.jupiter.api.Test; + +import javax.lang.model.element.ExecutableElement; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * {@link AnnotatedElementJSONElementVisitor} Test + * + * @author Mercy + * @see AnnotatedElementJSONElementVisitor + * @since 1.0.0 + */ +class AnnotatedElementJSONElementVisitorTest extends UtilTest { + + @Test + void test() { + String annotationClassName = Test.class.getName(); + AnnotatedElementJSONElementVisitor visitor = new AnnotatedElementJSONElementVisitor(super.processingEnv, annotationClassName) { + }; + + assertEquals(annotationClassName, visitor.getAnnotationClassName()); + + ExecutableElement testMethod = getMethod(AnnotatedElementJSONElementVisitorTest.class, "test"); + assertTrue(visitor.supports(testMethod)); + assertFalse(visitor.supports(super.testTypeElement)); + assertFalse(visitor.supports(NULL_ELEMENT)); + } + +} \ No newline at end of file diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/AnnotationUtilsTest.java b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/AnnotationUtilsTest.java similarity index 68% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/AnnotationUtilsTest.java rename to microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/AnnotationUtilsTest.java index 7aae66dc0..5b01b35da 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/AnnotationUtilsTest.java +++ b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/AnnotationUtilsTest.java @@ -14,14 +14,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor.util; - -import io.microsphere.annotation.processor.AbstractAnnotationProcessingTest; -import io.microsphere.annotation.processor.TestAnnotation; -import io.microsphere.annotation.processor.TestService; -import io.microsphere.annotation.processor.TestServiceImpl; -import io.microsphere.annotation.processor.model.Model; -import io.microsphere.annotation.processor.model.element.StringAnnotationValue; +package io.microsphere.lang.model.util; + +import io.microsphere.lang.model.element.StringAnnotationValue; +import io.microsphere.test.annotation.TestAnnotation; +import io.microsphere.test.model.Model; +import io.microsphere.test.service.TestService; +import io.microsphere.test.service.TestServiceImpl; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.Cacheable; @@ -52,40 +51,42 @@ import java.util.Map; import java.util.Map.Entry; -import static io.microsphere.annotation.processor.util.AnnotationUtils.EMPTY_ELEMENT_TYPE_ARRAY; -import static io.microsphere.annotation.processor.util.AnnotationUtils.findAllAnnotations; -import static io.microsphere.annotation.processor.util.AnnotationUtils.findAnnotation; -import static io.microsphere.annotation.processor.util.AnnotationUtils.findAnnotations; -import static io.microsphere.annotation.processor.util.AnnotationUtils.findMetaAnnotation; -import static io.microsphere.annotation.processor.util.AnnotationUtils.getAllAnnotations; -import static io.microsphere.annotation.processor.util.AnnotationUtils.getAnnotation; -import static io.microsphere.annotation.processor.util.AnnotationUtils.getAnnotations; -import static io.microsphere.annotation.processor.util.AnnotationUtils.getAttribute; -import static io.microsphere.annotation.processor.util.AnnotationUtils.getAttributeName; -import static io.microsphere.annotation.processor.util.AnnotationUtils.getAttributesMap; -import static io.microsphere.annotation.processor.util.AnnotationUtils.getElementTypes; -import static io.microsphere.annotation.processor.util.AnnotationUtils.getElementValue; -import static io.microsphere.annotation.processor.util.AnnotationUtils.getElementValues; -import static io.microsphere.annotation.processor.util.AnnotationUtils.getValue; -import static io.microsphere.annotation.processor.util.AnnotationUtils.isAnnotationPresent; -import static io.microsphere.annotation.processor.util.AnnotationUtils.matchesAnnotationTypeName; -import static io.microsphere.annotation.processor.util.AnnotationUtils.matchesAttributeMethod; -import static io.microsphere.annotation.processor.util.AnnotationUtils.matchesAttributeValue; -import static io.microsphere.annotation.processor.util.AnnotationUtils.matchesDefaultAttributeValue; -import static io.microsphere.annotation.processor.util.FieldUtils.findField; -import static io.microsphere.annotation.processor.util.MethodUtils.findMethod; -import static io.microsphere.annotation.processor.util.MethodUtils.getAllDeclaredMethods; import static io.microsphere.lang.function.Predicates.alwaysFalse; import static io.microsphere.lang.function.Predicates.alwaysTrue; +import static io.microsphere.lang.model.util.AnnotationUtils.EMPTY_ELEMENT_TYPE_ARRAY; +import static io.microsphere.lang.model.util.AnnotationUtils.findAllAnnotations; +import static io.microsphere.lang.model.util.AnnotationUtils.findAnnotation; +import static io.microsphere.lang.model.util.AnnotationUtils.findAnnotations; +import static io.microsphere.lang.model.util.AnnotationUtils.findMetaAnnotation; +import static io.microsphere.lang.model.util.AnnotationUtils.getAllAnnotations; +import static io.microsphere.lang.model.util.AnnotationUtils.getAnnotation; +import static io.microsphere.lang.model.util.AnnotationUtils.getAnnotations; +import static io.microsphere.lang.model.util.AnnotationUtils.getAttribute; +import static io.microsphere.lang.model.util.AnnotationUtils.getAttributeName; +import static io.microsphere.lang.model.util.AnnotationUtils.getAttributesMap; +import static io.microsphere.lang.model.util.AnnotationUtils.getElementTypes; +import static io.microsphere.lang.model.util.AnnotationUtils.getElementValue; +import static io.microsphere.lang.model.util.AnnotationUtils.getElementValues; +import static io.microsphere.lang.model.util.AnnotationUtils.getValue; +import static io.microsphere.lang.model.util.AnnotationUtils.isAnnotationPresent; +import static io.microsphere.lang.model.util.AnnotationUtils.matchesAnnotationTypeName; +import static io.microsphere.lang.model.util.AnnotationUtils.matchesAttributeMethod; +import static io.microsphere.lang.model.util.AnnotationUtils.matchesAttributeValue; +import static io.microsphere.lang.model.util.AnnotationUtils.matchesDefaultAttributeValue; +import static io.microsphere.lang.model.util.FieldUtils.findField; +import static io.microsphere.lang.model.util.MethodUtils.findMethod; +import static io.microsphere.lang.model.util.MethodUtils.getAllDeclaredMethods; import static io.microsphere.util.ArrayUtils.EMPTY_STRING_ARRAY; import static io.microsphere.util.ArrayUtils.ofArray; import static io.microsphere.util.StringUtils.EMPTY_STRING; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.TYPE; import static java.util.Collections.emptyMap; +import static javax.xml.ws.Service.Mode.PAYLOAD; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -96,7 +97,7 @@ * @author Mercy * @since 1.0.0 */ -class AnnotationUtilsTest extends AbstractAnnotationProcessingTest { +class AnnotationUtilsTest extends UtilTest { @Test void testGetAnnotation() { @@ -110,21 +111,21 @@ void testGetAnnotationWithClassName() { @Test void testGetAnnotationOnNull() { - assertNull(getAnnotation(testTypeElement, NULL_CLASS)); - assertNull(getAnnotation(testTypeElement.asType(), NULL_CLASS)); + assertNull(getAnnotation(super.testTypeElement, NULL_CLASS)); + assertNull(getAnnotation(super.testTypeElement.asType(), NULL_CLASS)); assertNull(getAnnotation(NULL_ANNOTATED_CONSTRUCT, NULL_CLASS)); } @Test void testGetAnnotationWithClassNameOnNull() { - assertNull(getAnnotation(testTypeElement, NULL_STRING)); - assertNull(getAnnotation(testTypeElement.asType(), NULL_STRING)); + assertNull(getAnnotation(super.testTypeElement, NULL_STRING)); + assertNull(getAnnotation(super.testTypeElement.asType(), NULL_STRING)); assertNull(getAnnotation(NULL_ANNOTATED_CONSTRUCT, NULL_STRING)); } @Test void testGetAnnotations() { - List annotations = getAnnotations(testTypeElement); + List annotations = getAnnotations(super.testTypeElement); assertEquals(4, annotations.size()); assertAnnotation(annotations.get(0), Service.class); assertAnnotation(annotations.get(1), ServiceMode.class); @@ -147,13 +148,13 @@ void testGetAnnotationsWithAnnotationClass() { @Test void testGetAnnotationsWithAnnotationClassOnNull() { assertTrue(getAnnotations(NULL_ANNOTATED_CONSTRUCT, NULL_CLASS).isEmpty()); - assertTrue(getAnnotations(testTypeElement, NULL_CLASS).isEmpty()); + assertTrue(getAnnotations(super.testTypeElement, NULL_CLASS).isEmpty()); assertTrue(getAnnotations(NULL_ANNOTATED_CONSTRUCT, Service.class).isEmpty()); } @Test void testGetAnnotationsWithAnnotationClassOnNotFound() { - List annotations = getAnnotations(testTypeElement, Override.class); + List annotations = getAnnotations(super.testTypeElement, Override.class); assertEquals(0, annotations.size()); } @@ -166,16 +167,16 @@ void testGetAnnotationsWithAnnotationClassName() { @Test void testGetAnnotationsWithAnnotationClassNameOnNull() { assertTrue(getAnnotations(NULL_ANNOTATED_CONSTRUCT, NULL_STRING).isEmpty()); - assertTrue(getAnnotations(testTypeElement, NULL_STRING).isEmpty()); + assertTrue(getAnnotations(super.testTypeElement, NULL_STRING).isEmpty()); assertTrue(getAnnotations(NULL_ANNOTATED_CONSTRUCT, "org.springframework.stereotype.Service").isEmpty()); } @Test void testGetAllAnnotations() { - List annotations = getAllAnnotations(testTypeElement); + List annotations = getAllAnnotations(super.testTypeElement); assertEquals(5, annotations.size()); - annotations = getAllAnnotations(testTypeMirror); + annotations = getAllAnnotations(super.testTypeMirror); assertEquals(5, annotations.size()); } @@ -187,16 +188,16 @@ void testGetAllAnnotationsOnNull() { @Test void testGetAllAnnotationsWithAnnotationClass() { - List annotations = getAllAnnotations(testTypeElement, Override.class); + List annotations = getAllAnnotations(super.testTypeElement, Override.class); assertEquals(0, annotations.size()); - annotations = getAllAnnotations(testTypeMirror, Override.class); + annotations = getAllAnnotations(super.testTypeMirror, Override.class); assertEquals(0, annotations.size()); - annotations = getAllAnnotations(testTypeElement, Service.class); + annotations = getAllAnnotations(super.testTypeElement, Service.class); assertEquals(1, annotations.size()); - annotations = getAllAnnotations(testTypeMirror, Service.class); + annotations = getAllAnnotations(super.testTypeMirror, Service.class); assertEquals(1, annotations.size()); annotations = getAllAnnotations(processingEnv, TestServiceImpl.class); @@ -213,17 +214,17 @@ void testGetAllAnnotationsWithAnnotationClassOnNull() { assertEmptyList(getAllAnnotations(NULL_TYPE_MIRROR, Service.class)); assertEmptyList(getAllAnnotations(NULL_PROCESSING_ENVIRONMENT, Service.class)); - assertEmptyList(getAllAnnotations(testTypeElement, NULL_CLASS)); - assertEmptyList(getAllAnnotations(testTypeMirror, NULL_CLASS)); + assertEmptyList(getAllAnnotations(super.testTypeElement, NULL_CLASS)); + assertEmptyList(getAllAnnotations(super.testTypeMirror, NULL_CLASS)); assertEmptyList(getAllAnnotations(processingEnv, NULL_CLASS)); } @Test void testGetAllAnnotationsWithAnnotationClassName() { - List annotations = getAllAnnotations(testTypeElement, "java.lang.Override"); + List annotations = getAllAnnotations(super.testTypeElement, "java.lang.Override"); assertEquals(0, annotations.size()); - annotations = getAllAnnotations(testTypeMirror, "org.springframework.stereotype.Service"); + annotations = getAllAnnotations(super.testTypeMirror, "org.springframework.stereotype.Service"); assertEquals(1, annotations.size()); } @@ -235,8 +236,8 @@ void testGetAllAnnotationsWithAnnotationClassNameOnNull() { assertTrue(getAllAnnotations(NULL_ELEMENT, "org.springframework.stereotype.Service").isEmpty()); assertTrue(getAllAnnotations(NULL_TYPE_MIRROR, "org.springframework.stereotype.Service").isEmpty()); - assertEmptyList(getAllAnnotations(testTypeElement, NULL_STRING)); - assertEmptyList(getAllAnnotations(testTypeMirror, NULL_STRING)); + assertEmptyList(getAllAnnotations(super.testTypeElement, NULL_STRING)); + assertEmptyList(getAllAnnotations(super.testTypeMirror, NULL_STRING)); } @Test @@ -247,23 +248,23 @@ void testFindAnnotation() { @Test void testFindAnnotationOnNotFound() { - assertNull(findAnnotation(testTypeMirror, Target.class)); - assertNull(findAnnotation(testTypeElement, Target.class)); - assertNull(findAnnotation(testTypeMirror, Override.class)); - assertNull(findAnnotation(testTypeElement, Override.class)); + assertNull(findAnnotation(super.testTypeMirror, Target.class)); + assertNull(findAnnotation(super.testTypeElement, Target.class)); + assertNull(findAnnotation(super.testTypeMirror, Override.class)); + assertNull(findAnnotation(super.testTypeElement, Override.class)); } @Test void testFindAnnotationOnNull() { assertNull(findAnnotation(NULL_ELEMENT, NULL_CLASS)); assertNull(findAnnotation(NULL_TYPE_MIRROR, NULL_CLASS)); - assertNull(findAnnotation(testTypeMirror, NULL_CLASS)); - assertNull(findAnnotation(testTypeElement, NULL_CLASS)); + assertNull(findAnnotation(super.testTypeMirror, NULL_CLASS)); + assertNull(findAnnotation(super.testTypeElement, NULL_CLASS)); assertNull(findAnnotation(NULL_ELEMENT, NULL_STRING)); assertNull(findAnnotation(NULL_TYPE_MIRROR, NULL_STRING)); - assertNull(findAnnotation(testTypeMirror, NULL_STRING)); - assertNull(findAnnotation(testTypeElement, NULL_STRING)); + assertNull(findAnnotation(super.testTypeMirror, NULL_STRING)); + assertNull(findAnnotation(super.testTypeElement, NULL_STRING)); } @Test @@ -275,19 +276,19 @@ void testFindMetaAnnotationWithAnnotationClass() { @Test void testFindMetaAnnotationWithAnnotationClassOnNotFound() { - assertNull(findMetaAnnotation(testTypeElement, Service.class)); + assertNull(findMetaAnnotation(super.testTypeElement, Service.class)); } @Test void testFindMetaAnnotationWithAnnotationClassNameOnNotFound() { - assertNull(findMetaAnnotation(testTypeElement, "org.springframework.stereotype.Service")); + assertNull(findMetaAnnotation(super.testTypeElement, "org.springframework.stereotype.Service")); } @Test void testFindMetaAnnotationWithAnnotationClassOnNull() { assertNull(findMetaAnnotation(NULL_ELEMENT, NULL_CLASS)); assertNull(findMetaAnnotation(NULL_ELEMENT, Service.class)); - assertNull(findMetaAnnotation(testTypeElement, NULL_CLASS)); + assertNull(findMetaAnnotation(super.testTypeElement, NULL_CLASS)); } @Test @@ -301,30 +302,30 @@ void testFindMetaAnnotationWithAnnotationClassName() { void testFindMetaAnnotationWithAnnotationClassNameOnNull() { assertNull(findMetaAnnotation(NULL_ELEMENT, NULL_STRING)); assertNull(findMetaAnnotation(NULL_ELEMENT, "test")); - assertNull(findMetaAnnotation(testTypeElement, NULL_STRING)); + assertNull(findMetaAnnotation(super.testTypeElement, NULL_STRING)); } @Test void testFindAllAnnotationsWithTypeMirror() { - List annotations = findAllAnnotations(testTypeMirror, alwaysTrue()); + List annotations = findAllAnnotations(super.testTypeMirror, alwaysTrue()); assertEquals(5, annotations.size()); - annotations = findAllAnnotations(testTypeMirror, alwaysFalse()); + annotations = findAllAnnotations(super.testTypeMirror, alwaysFalse()); assertEmptyList(annotations); } @Test void testFindAllAnnotationsWithTypeElement() { - List annotations = findAllAnnotations(testTypeElement, alwaysTrue()); + List annotations = findAllAnnotations(super.testTypeElement, alwaysTrue()); assertEquals(5, annotations.size()); - annotations = findAllAnnotations(testTypeElement, alwaysFalse()); + annotations = findAllAnnotations(super.testTypeElement, alwaysFalse()); assertEmptyList(annotations); } @Test void testFindAllAnnotationsWithMethod() { - ExecutableElement method = findMethod(testTypeElement, "echo", String.class); + ExecutableElement method = findMethod(super.testTypeElement, "echo", String.class); List annotations = findAllAnnotations(method, alwaysTrue()); assertEquals(1, annotations.size()); @@ -359,13 +360,13 @@ void testFindAllAnnotationsWithMethodParameters() { @Test void testFindAllAnnotationsWithField() { - VariableElement field = findField(testTypeElement, "context"); + VariableElement field = findField(super.testTypeElement, "context"); List annotations = findAllAnnotations(field, alwaysTrue()); assertEquals(1, annotations.size()); assertAnnotation(annotations.get(0), Autowired.class); - field = findField(testTypeElement, "environment"); + field = findField(super.testTypeElement, "environment"); annotations = findAllAnnotations(field, alwaysTrue()); assertEmptyList(annotations); } @@ -402,38 +403,38 @@ void testFindAllAnnotationsOnNull() { @Test void testMatchesAnnotationClass() { - AnnotationMirror annotation = findAnnotation(testTypeElement, Service.class); + AnnotationMirror annotation = findAnnotation(super.testTypeElement, Service.class); assertTrue(AnnotationUtils.matchesAnnotationType(annotation, Service.class)); } @Test void testMatchesAnnotationClassOnNull() { assertFalse(AnnotationUtils.matchesAnnotationType(NULL_ANNOTATION_MIRROR, Service.class)); - assertFalse(AnnotationUtils.matchesAnnotationType(findAnnotation(testTypeElement, Service.class), NULL_CLASS)); + assertFalse(AnnotationUtils.matchesAnnotationType(findAnnotation(super.testTypeElement, Service.class), NULL_CLASS)); } @Test void testMatchesAnnotationTypeName() { - AnnotationMirror annotation = findAnnotation(testTypeElement, "org.springframework.stereotype.Service"); + AnnotationMirror annotation = findAnnotation(super.testTypeElement, "org.springframework.stereotype.Service"); assertTrue(matchesAnnotationTypeName(annotation, "org.springframework.stereotype.Service")); } @Test void testMatchesAnnotationTypeNameOnNull() { assertFalse(matchesAnnotationTypeName(NULL_ANNOTATION_MIRROR, "org.springframework.stereotype.Service")); - assertFalse(matchesAnnotationTypeName(findAnnotation(testTypeElement, "org.springframework.stereotype.Service"), NULL_STRING)); + assertFalse(matchesAnnotationTypeName(findAnnotation(super.testTypeElement, "org.springframework.stereotype.Service"), NULL_STRING)); } @Test void testGetAttribute() { - assertEquals("testService", getAttribute(findAnnotation(testTypeElement, Service.class), "value")); - assertEquals("testService", getAttribute(findAnnotation(testTypeElement, Service.class), "value", false)); - assertEquals("/echo", getAttribute(findAnnotation(testTypeElement, Path.class), "value")); + assertEquals("testService", getAttribute(findAnnotation(super.testTypeElement, Service.class), "value")); + assertEquals("testService", getAttribute(findAnnotation(super.testTypeElement, Service.class), "value", false)); + assertEquals("/echo", getAttribute(findAnnotation(super.testTypeElement, Path.class), "value")); - assertNull(getAttribute(findAnnotation(testTypeElement, Path.class), NULL_STRING)); - assertNull(getAttribute(findAnnotation(testTypeElement, NULL_CLASS), NULL_STRING)); + assertNull(getAttribute(findAnnotation(super.testTypeElement, Path.class), NULL_STRING)); + assertNull(getAttribute(findAnnotation(super.testTypeElement, NULL_CLASS), NULL_STRING)); - ExecutableElement echoMethod = findMethod(testTypeElement, "echo", String.class); + ExecutableElement echoMethod = findMethod(super.testTypeElement, "echo", String.class); AnnotationMirror cacheableAnnotation = findAnnotation(echoMethod, Cacheable.class); String[] cacheNames = getAttribute(cacheableAnnotation, "cacheNames"); assertArrayEquals(ofArray("cache-1", "cache-2"), cacheNames); @@ -456,54 +457,54 @@ void testGetValue() { @Test void testIsAnnotationPresentOnAnnotationClass() { - assertTrue(isAnnotationPresent(testTypeElement, Service.class)); - assertTrue(isAnnotationPresent(testTypeElement, Component.class)); - assertTrue(isAnnotationPresent(testTypeElement, ServiceMode.class)); - assertTrue(isAnnotationPresent(testTypeElement, Inherited.class)); - assertTrue(isAnnotationPresent(testTypeElement, Documented.class)); + assertTrue(isAnnotationPresent(super.testTypeElement, Service.class)); + assertTrue(isAnnotationPresent(super.testTypeElement, Component.class)); + assertTrue(isAnnotationPresent(super.testTypeElement, ServiceMode.class)); + assertTrue(isAnnotationPresent(super.testTypeElement, Inherited.class)); + assertTrue(isAnnotationPresent(super.testTypeElement, Documented.class)); } @Test void testIsAnnotationPresentOnAnnotationClassOnNull() { assertFalse(isAnnotationPresent(NULL_ELEMENT, Service.class)); - assertFalse(isAnnotationPresent(testTypeElement, NULL_CLASS)); - assertFalse(isAnnotationPresent(testTypeElement, Override.class)); + assertFalse(isAnnotationPresent(super.testTypeElement, NULL_CLASS)); + assertFalse(isAnnotationPresent(super.testTypeElement, Override.class)); } @Test void testIsAnnotationPresentOnAnnotationClassName() { - assertTrue(isAnnotationPresent(testTypeElement, "org.springframework.stereotype.Service")); - assertTrue(isAnnotationPresent(testTypeElement, "org.springframework.stereotype.Component")); - assertTrue(isAnnotationPresent(testTypeElement, "javax.xml.ws.ServiceMode")); - assertTrue(isAnnotationPresent(testTypeElement, "java.lang.annotation.Inherited")); - assertTrue(isAnnotationPresent(testTypeElement, "java.lang.annotation.Documented")); + assertTrue(isAnnotationPresent(super.testTypeElement, "org.springframework.stereotype.Service")); + assertTrue(isAnnotationPresent(super.testTypeElement, "org.springframework.stereotype.Component")); + assertTrue(isAnnotationPresent(super.testTypeElement, "javax.xml.ws.ServiceMode")); + assertTrue(isAnnotationPresent(super.testTypeElement, "java.lang.annotation.Inherited")); + assertTrue(isAnnotationPresent(super.testTypeElement, "java.lang.annotation.Documented")); } @Test void testIsAnnotationPresentOnAnnotationClassNameOnNull() { assertFalse(isAnnotationPresent(NULL_ELEMENT, "org.springframework.stereotype.Service")); - assertFalse(isAnnotationPresent(testTypeElement, NULL_STRING)); - assertFalse(isAnnotationPresent(testTypeElement, "java.lang.Override")); + assertFalse(isAnnotationPresent(super.testTypeElement, NULL_STRING)); + assertFalse(isAnnotationPresent(super.testTypeElement, "java.lang.Override")); } @Test void testFindAnnotations() { - List annotations = findAnnotations(testTypeElement); + List annotations = findAnnotations(super.testTypeElement); assertEquals(4, annotations.size()); assertAnnotation(annotations.get(0), Service.class); assertAnnotation(annotations.get(1), ServiceMode.class); assertAnnotation(annotations.get(2), ComponentScans.class); assertAnnotation(annotations.get(3), TestAnnotation.class); - annotations = findAnnotations(testTypeElement, alwaysTrue()); + annotations = findAnnotations(super.testTypeElement, alwaysTrue()); assertEquals(4, annotations.size()); assertAnnotation(annotations.get(0), Service.class); assertAnnotation(annotations.get(1), ServiceMode.class); assertAnnotation(annotations.get(2), ComponentScans.class); assertAnnotation(annotations.get(3), TestAnnotation.class); - annotations = findAnnotations(testTypeElement, alwaysFalse()); + annotations = findAnnotations(super.testTypeElement, alwaysFalse()); assertEmptyList(annotations); } @@ -519,7 +520,7 @@ void testFindAnnotationsOnNull() { @Test void testGetAttributeName() { - Map elementValues = getElementValues(testTypeElement, TestAnnotation.class); + Map elementValues = getElementValues(super.testTypeElement, TestAnnotation.class); for (Entry entry : elementValues.entrySet()) { ExecutableElement attributeMethod = entry.getKey(); assertEquals(attributeMethod.getSimpleName().toString(), getAttributeName(attributeMethod)); @@ -528,7 +529,7 @@ void testGetAttributeName() { @Test void testMatchesAttributeMethod() { - Map elementValues = getElementValues(testTypeElement, TestAnnotation.class); + Map elementValues = getElementValues(super.testTypeElement, TestAnnotation.class); for (Entry entry : elementValues.entrySet()) { ExecutableElement attributeMethod = entry.getKey(); assertTrue(matchesAttributeMethod(attributeMethod, getAttributeName(attributeMethod))); @@ -539,7 +540,7 @@ void testMatchesAttributeMethod() { void testMatchesAttributeMethodOnNull() { assertFalse(matchesAttributeMethod(null, null)); - Map elementValues = getElementValues(testTypeElement, TestAnnotation.class); + Map elementValues = getElementValues(super.testTypeElement, TestAnnotation.class); for (Entry entry : elementValues.entrySet()) { ExecutableElement attributeMethod = entry.getKey(); assertFalse(matchesAttributeMethod(attributeMethod, null)); @@ -548,7 +549,7 @@ void testMatchesAttributeMethodOnNull() { @Test void testMatchesAttributeValue() { - Map elementValues = getElementValues(testTypeElement, TestAnnotation.class); + Map elementValues = getElementValues(super.testTypeElement, TestAnnotation.class); for (Entry entry : elementValues.entrySet()) { AnnotationValue annotationValue = entry.getValue(); assertTrue(matchesAttributeValue(annotationValue, annotationValue)); @@ -563,26 +564,36 @@ void testMatchesAttributeValueOnNull() { assertTrue(matchesAttributeValue(null, null)); assertFalse(matchesAttributeValue(null, (Object) null)); - Map elementValues = getElementValues(testTypeElement, TestAnnotation.class); + Map elementValues = getElementValues(super.testTypeElement, TestAnnotation.class); for (Entry entry : elementValues.entrySet()) { AnnotationValue annotationValue = entry.getValue(); assertFalse(matchesAttributeValue(annotationValue, null)); assertFalse(matchesAttributeValue(annotationValue, (Object) null)); + assertFalse(matchesAttributeValue(null, annotationValue)); } } @Test void testMatchesDefaultAttributeValue() { - Map elementValues = getElementValues(testTypeElement, ServiceMode.class); + Map elementValues = getElementValues(super.testTypeElement, ServiceMode.class); for (Entry entry : elementValues.entrySet()) { ExecutableElement attributeMethod = entry.getKey(); assertTrue(matchesDefaultAttributeValue(attributeMethod, attributeMethod.getDefaultValue())); } } + @Test + void testMatchesDefaultAttributeValueOnNull() { + Map elementValues = getElementValues(super.testTypeElement, ServiceMode.class); + for (Entry entry : elementValues.entrySet()) { + ExecutableElement attributeMethod = entry.getKey(); + assertFalse(matchesDefaultAttributeValue(NULL_METHOD, attributeMethod.getDefaultValue())); + } + } + @Test void testGetElementValue() { - Map elementValues = getElementValues(testTypeElement, TestAnnotation.class); + Map elementValues = getElementValues(super.testTypeElement, TestAnnotation.class); for (Entry entry : elementValues.entrySet()) { ExecutableElement attributeMethod = entry.getKey(); String attributeName = getAttributeName(attributeMethod); @@ -590,11 +601,29 @@ void testGetElementValue() { } assertNull(getElementValue(elementValues, "unknown")); + + AnnotationMirror annotation = findAnnotation(super.testTypeElement, ServiceMode.class); + Entry elementValue = getElementValue(annotation, "value", true); + + assertAttributeEntry(elementValue, "value", PAYLOAD); + + elementValue = getElementValue(annotation, "value", false); + assertNull(elementValue); + } + + @Test + void testGetElementValueOnNotFound() { + AnnotationMirror annotation = findAnnotation(super.testTypeElement, ServiceMode.class); + Entry elementValue = getElementValue(annotation, "z", true); + assertNull(elementValue); + + elementValue = getElementValue(annotation, "z", false); + assertNull(elementValue); } @Test void testGetElementValueOnEmptyElementValues() { - AnnotationMirror annotation = findAnnotation(testTypeElement, ServiceMode.class); + AnnotationMirror annotation = findAnnotation(super.testTypeElement, ServiceMode.class); Map elementValues = annotation.getElementValues(); assertNull(getElementValue(elementValues, "value")); } @@ -606,14 +635,14 @@ void testGetElementValueOnNull() { @Test void testGetElementValuesMapOnAnnotatedClass() { - Map attributesMap = getAttributesMap(testTypeElement, Service.class); + Map attributesMap = getAttributesMap(super.testTypeElement, Service.class); assertEquals(1, attributesMap.size()); assertEquals("testService", attributesMap.get("value")); } @Test void testGetElementValuesMapOnAnnotatedMethod() { - ExecutableElement method = findMethod(testTypeElement, "echo", String.class); + ExecutableElement method = findMethod(super.testTypeElement, "echo", String.class); Map attributesMap = getAttributesMap(method, Cacheable.class); assertEquals(9, attributesMap.size()); assertArrayEquals(ofArray("cache-1", "cache-2"), (String[]) attributesMap.get("cacheNames")); @@ -621,7 +650,7 @@ void testGetElementValuesMapOnAnnotatedMethod() { @Test void testGetElementValuesMapOnRepeatableAnnotation() { - Map attributesMap = getAttributesMap(testTypeElement, ComponentScans.class); + Map attributesMap = getAttributesMap(super.testTypeElement, ComponentScans.class); assertEquals(1, attributesMap.size()); ComponentScans componentScans = testClass.getAnnotation(ComponentScans.class); @@ -635,7 +664,7 @@ void testGetElementValuesMapOnNull() { Map attributesMap = getAttributesMap(null, null); assertSame(emptyMap(), attributesMap); - attributesMap = getAttributesMap(testTypeElement, null); + attributesMap = getAttributesMap(super.testTypeElement, null); assertSame(emptyMap(), attributesMap); attributesMap = getAttributesMap(null); @@ -644,16 +673,16 @@ void testGetElementValuesMapOnNull() { @Test void testGetElementValuesOnAnnotatedClass() { - Map elementValues = getElementValues(testTypeElement, Service.class); + Map elementValues = getElementValues(super.testTypeElement, Service.class); assertServiceAttributes(elementValues); - elementValues = getElementValues(testTypeElement, Service.class, false); + elementValues = getElementValues(super.testTypeElement, Service.class, false); assertServiceAttributes(elementValues); } @Test void testGetElementValuesOnAnnotatedMethod() { - ExecutableElement method = findMethod(testTypeElement, "echo", String.class); + ExecutableElement method = findMethod(super.testTypeElement, "echo", String.class); Map elementValues = getElementValues(method, Cacheable.class, false); assertEquals(1, elementValues.size()); assertAttributeEntry(elementValues, "cacheNames", ofArray("cache-1", "cache-2")); @@ -687,7 +716,7 @@ void testGetElementTypes() { } void assertElementTypes(Class annotationClass, ElementType... expectedElementTypes) { - AnnotationMirror annotationMirror = findAnnotation(this.testTypeElement, annotationClass); + AnnotationMirror annotationMirror = findAnnotation(super.testTypeElement, annotationClass); assertArrayEquals(expectedElementTypes, getElementTypes(annotationMirror)); } @@ -712,19 +741,26 @@ void assertAttributeEntry(Map attributes, St } } - void assertAttributeEntry(Entry attributeEntry, String attributeName, Object attributeValue) { + void assertAttributeEntry(Entry attributeEntry, String attributeName, Object expectedAttributeValue) { + assertNotNull(attributeEntry); + ExecutableElement attributeMethod = attributeEntry.getKey(); - AnnotationValue annotationValue = attributeEntry.getValue(); + AnnotationValue attributeValue = attributeEntry.getValue(); + assertNotNull(attributeMethod); + assertNotNull(attributeValue); + assertEquals(attributeName, getAttributeName(attributeMethod)); + assertTrue(matchesAttributeMethod(attributeMethod, getAttributeName(attributeMethod))); + Object value = getAttribute(attributeEntry); Class attributeValueClass = value.getClass(); if (attributeValueClass.isArray()) { Class componentType = attributeValueClass.getComponentType(); if (String.class.equals(componentType)) { - assertArrayEquals((String[]) attributeValue, (String[]) value); + assertArrayEquals((String[]) expectedAttributeValue, (String[]) value); } } else { - assertEquals(attributeValue, value); + assertEquals(expectedAttributeValue, value); } } @@ -737,30 +773,30 @@ private void assertFindMetaAnnotation(Element element, String annotationClassNam } private void assertFindAnnotation(Class annotationClass) { - assertAnnotation(findAnnotation(testTypeMirror, annotationClass), annotationClass); - assertAnnotation(findAnnotation(testTypeElement, annotationClass), annotationClass); - assertAnnotation(findAnnotation(testTypeMirror, annotationClass.getName()), annotationClass); - assertAnnotation(findAnnotation(testTypeElement, annotationClass.getName()), annotationClass); + assertAnnotation(findAnnotation(super.testTypeMirror, annotationClass), annotationClass); + assertAnnotation(findAnnotation(super.testTypeElement, annotationClass), annotationClass); + assertAnnotation(findAnnotation(super.testTypeMirror, annotationClass.getName()), annotationClass); + assertAnnotation(findAnnotation(super.testTypeElement, annotationClass.getName()), annotationClass); } private void asserGetAnnotation(Class annotationClass) { - AnnotationMirror annotation = getAnnotation(testTypeElement, annotationClass); + AnnotationMirror annotation = getAnnotation(super.testTypeElement, annotationClass); assertAnnotation(annotation, annotationClass); } private void asserGetAnnotation(String annotationClassName) { - AnnotationMirror annotation = getAnnotation(testTypeElement, annotationClassName); + AnnotationMirror annotation = getAnnotation(super.testTypeElement, annotationClassName); assertAnnotation(annotation, annotationClassName); } private void assertGetAnnotations(Class annotationClass) { - List annotations = getAnnotations(testTypeElement, annotationClass); + List annotations = getAnnotations(super.testTypeElement, annotationClass); assertEquals(1, annotations.size()); assertAnnotation(annotations.get(0), annotationClass); } private void assertGetAnnotations(String annotationClassName) { - List annotations = getAnnotations(testTypeElement, annotationClassName); + List annotations = getAnnotations(super.testTypeElement, annotationClassName); assertEquals(1, annotations.size()); assertAnnotation(annotations.get(0), annotationClassName); } diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/ClassUtilsTest.java b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/ClassUtilsTest.java similarity index 81% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/ClassUtilsTest.java rename to microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/ClassUtilsTest.java index 3785041ad..c6857d5ed 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/ClassUtilsTest.java +++ b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/ClassUtilsTest.java @@ -15,15 +15,15 @@ * limitations under the License. */ -package io.microsphere.annotation.processor.util; +package io.microsphere.lang.model.util; -import io.microsphere.annotation.processor.AbstractAnnotationProcessingTest; import org.junit.jupiter.api.Test; import org.springframework.context.annotation.ComponentScan; -import static io.microsphere.annotation.processor.util.ClassUtils.getClassName; -import static io.microsphere.annotation.processor.util.ClassUtils.loadClass; +import static io.microsphere.lang.model.util.ClassUtils.getClassName; +import static io.microsphere.lang.model.util.ClassUtils.loadClass; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertSame; /** @@ -33,7 +33,7 @@ * @see ClassUtils * @since 1.0.0 */ -class ClassUtilsTest extends AbstractAnnotationProcessingTest { +class ClassUtilsTest extends UtilTest { @Test void testGetClassName() { @@ -48,5 +48,6 @@ void testLoadClassOnTypeMirror() { @Test void testLoadClass() { assertSame(ComponentScan.Filter.class, loadClass("org.springframework.context.annotation.ComponentScan.Filter")); + assertNull(loadClass("not-found-class")); } } diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/ConstructorUtilsTest.java b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/ConstructorUtilsTest.java similarity index 91% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/ConstructorUtilsTest.java rename to microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/ConstructorUtilsTest.java index 09aac37d9..a4b513650 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/ConstructorUtilsTest.java +++ b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/ConstructorUtilsTest.java @@ -15,10 +15,9 @@ * limitations under the License. */ -package io.microsphere.annotation.processor.util; +package io.microsphere.lang.model.util; -import io.microsphere.annotation.processor.AbstractAnnotationProcessingTest; import org.junit.jupiter.api.Test; import org.springframework.core.env.Environment; @@ -26,12 +25,12 @@ import java.io.Serializable; import java.util.List; -import static io.microsphere.annotation.processor.util.ConstructorUtils.findConstructor; -import static io.microsphere.annotation.processor.util.ConstructorUtils.findDeclaredConstructors; -import static io.microsphere.annotation.processor.util.ConstructorUtils.getDeclaredConstructors; -import static io.microsphere.annotation.processor.util.ElementUtils.matchParameterTypes; import static io.microsphere.lang.function.Predicates.alwaysFalse; import static io.microsphere.lang.function.Predicates.alwaysTrue; +import static io.microsphere.lang.model.util.ConstructorUtils.findConstructor; +import static io.microsphere.lang.model.util.ConstructorUtils.findDeclaredConstructors; +import static io.microsphere.lang.model.util.ConstructorUtils.getDeclaredConstructors; +import static io.microsphere.lang.model.util.ElementUtils.matchParameterTypes; import static java.util.Collections.emptyList; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; @@ -45,7 +44,7 @@ * @see ConstructorUtils * @since 1.0.0 */ -class ConstructorUtilsTest extends AbstractAnnotationProcessingTest { +class ConstructorUtilsTest extends UtilTest { @Test void testGetDeclaredConstructors() { diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/ElementUtilsTest.java b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/ElementUtilsTest.java similarity index 77% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/ElementUtilsTest.java rename to microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/ElementUtilsTest.java index 91cb83a6f..b65ea7b2c 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/ElementUtilsTest.java +++ b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/ElementUtilsTest.java @@ -15,41 +15,43 @@ * limitations under the License. */ -package io.microsphere.annotation.processor.util; +package io.microsphere.lang.model.util; -import io.microsphere.annotation.processor.AbstractAnnotationProcessingTest; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ReflectiveInvocationContext; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.VariableElement; import java.lang.annotation.ElementType; +import java.lang.reflect.Method; import java.util.List; -import static io.microsphere.annotation.processor.util.ElementUtils.filterElements; -import static io.microsphere.annotation.processor.util.ElementUtils.hasModifiers; -import static io.microsphere.annotation.processor.util.ElementUtils.isClass; -import static io.microsphere.annotation.processor.util.ElementUtils.isDeclaredType; -import static io.microsphere.annotation.processor.util.ElementUtils.isExecutable; -import static io.microsphere.annotation.processor.util.ElementUtils.isField; -import static io.microsphere.annotation.processor.util.ElementUtils.isInitializer; -import static io.microsphere.annotation.processor.util.ElementUtils.isInterface; -import static io.microsphere.annotation.processor.util.ElementUtils.isMember; -import static io.microsphere.annotation.processor.util.ElementUtils.isPublicNonStatic; -import static io.microsphere.annotation.processor.util.ElementUtils.isVariable; -import static io.microsphere.annotation.processor.util.ElementUtils.matchParameterTypeNames; -import static io.microsphere.annotation.processor.util.ElementUtils.matchParameterTypes; -import static io.microsphere.annotation.processor.util.ElementUtils.matchesElementKind; -import static io.microsphere.annotation.processor.util.ElementUtils.matchesElementType; -import static io.microsphere.annotation.processor.util.ElementUtils.toElementKind; -import static io.microsphere.annotation.processor.util.MemberUtils.getAllDeclaredMembers; -import static io.microsphere.annotation.processor.util.MemberUtils.getDeclaredMembers; -import static io.microsphere.annotation.processor.util.MethodUtils.findMethod; import static io.microsphere.collection.ListUtils.ofList; import static io.microsphere.lang.function.Predicates.alwaysFalse; import static io.microsphere.lang.function.Predicates.alwaysTrue; +import static io.microsphere.lang.model.util.ElementUtils.filterElements; +import static io.microsphere.lang.model.util.ElementUtils.hasModifiers; +import static io.microsphere.lang.model.util.ElementUtils.isClass; +import static io.microsphere.lang.model.util.ElementUtils.isDeclaredType; +import static io.microsphere.lang.model.util.ElementUtils.isExecutable; +import static io.microsphere.lang.model.util.ElementUtils.isField; +import static io.microsphere.lang.model.util.ElementUtils.isInitializer; +import static io.microsphere.lang.model.util.ElementUtils.isInterface; +import static io.microsphere.lang.model.util.ElementUtils.isMember; +import static io.microsphere.lang.model.util.ElementUtils.isPublicNonStatic; +import static io.microsphere.lang.model.util.ElementUtils.isVariable; +import static io.microsphere.lang.model.util.ElementUtils.matchParameterTypeNames; +import static io.microsphere.lang.model.util.ElementUtils.matchParameterTypes; +import static io.microsphere.lang.model.util.ElementUtils.matchesElementKind; +import static io.microsphere.lang.model.util.ElementUtils.matchesElementType; +import static io.microsphere.lang.model.util.ElementUtils.toElementKind; +import static io.microsphere.lang.model.util.MemberUtils.getAllDeclaredMembers; +import static io.microsphere.lang.model.util.MemberUtils.getDeclaredMembers; +import static io.microsphere.lang.model.util.MethodUtils.findMethod; import static java.lang.annotation.ElementType.PACKAGE; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.ElementType.TYPE_USE; @@ -70,7 +72,7 @@ import static javax.lang.model.element.ElementKind.PARAMETER; import static javax.lang.model.element.ElementKind.RESOURCE_VARIABLE; import static javax.lang.model.element.ElementKind.STATIC_INIT; -import static javax.lang.model.element.Modifier.PRIVATE; +import static javax.lang.model.element.Modifier.PROTECTED; import static javax.lang.model.util.ElementFilter.fieldsIn; import static javax.lang.model.util.ElementFilter.methodsIn; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -86,26 +88,26 @@ * @see ElementUtils * @since 1.0.0 */ -class ElementUtilsTest extends AbstractAnnotationProcessingTest { +class ElementUtilsTest extends UtilTest { private ExecutableElement echoMethod; @Override - protected void beforeTest() { - super.beforeTest(); + protected void beforeTest(ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) { + super.beforeTest(invocationContext, extensionContext); this.echoMethod = findMethod(testTypeElement, "echo", "java.lang.String"); } @Test void testMatchesElementTypeElementKind() { assertTrue(matchesElementKind(echoMethod, METHOD)); - assertFalse(matchesElementKind(echoMethod, FIELD)); + assertFalse(matchesElementKind(this.echoMethod, FIELD)); } @Test void testMatchesElementTypeElementKindOnNull() { assertFalse(matchesElementKind(NULL_ELEMENT, FIELD)); - assertFalse(matchesElementKind(echoMethod, NULL_ELEMENT_KIND)); + assertFalse(matchesElementKind(this.echoMethod, NULL_ELEMENT_KIND)); } @Test @@ -125,7 +127,7 @@ void testIsPublicNonStaticOnNull() { void testHasModifiers() { List members = getAllDeclaredMembers(testTypeElement.asType()); List fields = fieldsIn(members); - assertTrue(hasModifiers(fields.get(0), PRIVATE)); + assertTrue(hasModifiers(fields.get(0), PROTECTED)); } @Test @@ -279,7 +281,8 @@ void testMatchesElementTypeWithArray() { @Test void testMatchesElementTypeWithElement() { - matchesElementType(this.testTypeElement, TYPE); + assertTrue(matchesElementType(this.testTypeElement, TYPE)); + assertFalse(matchesElementType(this.testTypeElement, PACKAGE)); } @Test @@ -304,33 +307,35 @@ void testFilterElements() { @Test void testFilterElementsOnNull() { assertEmptyList(filterElements(NULL_LIST, alwaysTrue())); - List methods = ofList(echoMethod); + List methods = ofList(this.echoMethod); assertSame(emptyList(), filterElements(methods, NULL_PREDICATE_ARRAY)); } @Test void testFilterElementsOnEmpty() { assertEmptyList(filterElements(emptyList(), alwaysTrue())); - List methods = ofList(echoMethod); + List methods = ofList(this.echoMethod); assertEquals(methods, filterElements(methods)); } @Test void testMatchParameterTypes() { - assertTrue(matchParameterTypes(echoMethod.getParameters(), String.class)); - assertFalse(matchParameterTypes(echoMethod.getParameters(), Object.class)); + assertTrue(matchParameterTypes(this.echoMethod.getParameters(), String.class)); + assertFalse(matchParameterTypes(this.echoMethod.getParameters(), Object.class)); } @Test void testMatchParameterTypesOnNull() { assertFalse(matchParameterTypes(NULL_LIST, String.class)); assertFalse(matchParameterTypes(emptyList(), NULL_CLASS_ARRAY)); + assertFalse(matchParameterTypes(NULL_METHOD, String.class)); + assertFalse(matchParameterTypes(this.echoMethod, NULL_CLASS_ARRAY)); } @Test void testMatchParameterTypeNames() { - assertTrue(matchParameterTypeNames(echoMethod.getParameters(), "java.lang.String")); - assertFalse(matchParameterTypeNames(echoMethod.getParameters(), "java.lang.Object")); + assertTrue(matchParameterTypeNames(this.echoMethod.getParameters(), "java.lang.String")); + assertFalse(matchParameterTypeNames(this.echoMethod.getParameters(), "java.lang.Object")); } @Test diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/ExecutableElementComparatorTest.java b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/ExecutableElementComparatorTest.java similarity index 85% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/ExecutableElementComparatorTest.java rename to microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/ExecutableElementComparatorTest.java index dfd4eaa25..9043220bb 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/ExecutableElementComparatorTest.java +++ b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/ExecutableElementComparatorTest.java @@ -1,15 +1,14 @@ -package io.microsphere.annotation.processor.util; +package io.microsphere.lang.model.util; -import io.microsphere.annotation.processor.AbstractAnnotationProcessingTest; -import io.microsphere.annotation.processor.TestService; +import io.microsphere.test.service.TestService; import org.junit.jupiter.api.Test; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; import java.lang.reflect.Type; -import static io.microsphere.annotation.processor.util.ExecutableElementComparator.INSTANCE; -import static io.microsphere.annotation.processor.util.MethodUtils.findMethod; +import static io.microsphere.lang.model.util.ExecutableElementComparator.INSTANCE; +import static io.microsphere.lang.model.util.MethodUtils.findMethod; import static org.junit.jupiter.api.Assertions.assertEquals; /** @@ -19,7 +18,7 @@ * @see ExecutableElementComparator * @since 1.0.0 */ -class ExecutableElementComparatorTest extends AbstractAnnotationProcessingTest { +class ExecutableElementComparatorTest extends UtilTest { private final ExecutableElementComparator comparator = INSTANCE; diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/FieldUtilsTest.java b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/FieldUtilsTest.java similarity index 90% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/FieldUtilsTest.java rename to microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/FieldUtilsTest.java index 7477f52ee..afa535fb0 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/FieldUtilsTest.java +++ b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/FieldUtilsTest.java @@ -14,11 +14,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor.util; +package io.microsphere.lang.model.util; -import io.microsphere.annotation.processor.AbstractAnnotationProcessingTest; -import io.microsphere.annotation.processor.model.Color; -import io.microsphere.annotation.processor.model.Model; +import io.microsphere.test.model.Color; +import io.microsphere.test.model.Model; import org.junit.jupiter.api.Test; import javax.lang.model.element.ExecutableElement; @@ -33,22 +32,22 @@ import java.util.List; import java.util.concurrent.TimeUnit; -import static io.microsphere.annotation.processor.util.FieldUtils.equalsFieldName; -import static io.microsphere.annotation.processor.util.FieldUtils.filterDeclaredFields; -import static io.microsphere.annotation.processor.util.FieldUtils.findAllDeclaredFields; -import static io.microsphere.annotation.processor.util.FieldUtils.findDeclaredFields; -import static io.microsphere.annotation.processor.util.FieldUtils.findField; -import static io.microsphere.annotation.processor.util.FieldUtils.getAllDeclaredFields; -import static io.microsphere.annotation.processor.util.FieldUtils.getAllNonStaticFields; -import static io.microsphere.annotation.processor.util.FieldUtils.getDeclaredField; -import static io.microsphere.annotation.processor.util.FieldUtils.getDeclaredFields; -import static io.microsphere.annotation.processor.util.FieldUtils.getNonStaticFields; -import static io.microsphere.annotation.processor.util.FieldUtils.isEnumMemberField; -import static io.microsphere.annotation.processor.util.FieldUtils.isField; -import static io.microsphere.annotation.processor.util.FieldUtils.isNonStaticField; -import static io.microsphere.annotation.processor.util.MethodUtils.findMethod; import static io.microsphere.lang.function.Predicates.alwaysFalse; import static io.microsphere.lang.function.Predicates.alwaysTrue; +import static io.microsphere.lang.model.util.FieldUtils.equalsFieldName; +import static io.microsphere.lang.model.util.FieldUtils.filterDeclaredFields; +import static io.microsphere.lang.model.util.FieldUtils.findAllDeclaredFields; +import static io.microsphere.lang.model.util.FieldUtils.findDeclaredFields; +import static io.microsphere.lang.model.util.FieldUtils.findField; +import static io.microsphere.lang.model.util.FieldUtils.getAllDeclaredFields; +import static io.microsphere.lang.model.util.FieldUtils.getAllNonStaticFields; +import static io.microsphere.lang.model.util.FieldUtils.getDeclaredField; +import static io.microsphere.lang.model.util.FieldUtils.getDeclaredFields; +import static io.microsphere.lang.model.util.FieldUtils.getNonStaticFields; +import static io.microsphere.lang.model.util.FieldUtils.isEnumMemberField; +import static io.microsphere.lang.model.util.FieldUtils.isField; +import static io.microsphere.lang.model.util.FieldUtils.isNonStaticField; +import static io.microsphere.lang.model.util.MethodUtils.findMethod; import static io.microsphere.util.StringUtils.EMPTY_STRING; import static javax.lang.model.element.Modifier.FINAL; import static javax.lang.model.element.Modifier.PRIVATE; @@ -65,7 +64,7 @@ * @author Mercy * @since 1.0.0 */ -class FieldUtilsTest extends AbstractAnnotationProcessingTest { +class FieldUtilsTest extends UtilTest { @Test void testGetDeclaredField() { diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/util/JSONAnnotationValueVisitorTest.java b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/JSONAnnotationValueVisitorTest.java similarity index 83% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/util/JSONAnnotationValueVisitorTest.java rename to microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/JSONAnnotationValueVisitorTest.java index 094b1460c..d89d3c732 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/util/JSONAnnotationValueVisitorTest.java +++ b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/JSONAnnotationValueVisitorTest.java @@ -15,19 +15,21 @@ * limitations under the License. */ -package io.microsphere.annotation.processor.model.util; +package io.microsphere.lang.model.util; -import io.microsphere.annotation.processor.AbstractAnnotationProcessingTest; -import io.microsphere.annotation.processor.TestAnnotation; +import io.microsphere.test.annotation.TestAnnotation; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ReflectiveInvocationContext; import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.ExecutableElement; +import java.lang.reflect.Method; import java.util.Map; -import static io.microsphere.annotation.processor.util.AnnotationUtils.getElementValue; -import static io.microsphere.annotation.processor.util.AnnotationUtils.getElementValues; +import static io.microsphere.lang.model.util.AnnotationUtils.getElementValue; +import static io.microsphere.lang.model.util.AnnotationUtils.getElementValues; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertSame; @@ -38,7 +40,7 @@ * @see JSONAnnotationValueVisitor * @since 1.0.0 */ -class JSONAnnotationValueVisitorTest extends AbstractAnnotationProcessingTest { +class JSONAnnotationValueVisitorTest extends UtilTest { private StringBuilder jsonBuilder; @@ -46,8 +48,9 @@ class JSONAnnotationValueVisitorTest extends AbstractAnnotationProcessingTest { private Map testAnnotationAttributes; - protected void beforeTest() { - super.beforeTest(); + @Override + protected void beforeTest(ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) { + super.beforeTest(invocationContext,extensionContext); this.jsonBuilder = new StringBuilder(); this.visitor = new JSONAnnotationValueVisitor(jsonBuilder); this.testAnnotationAttributes = getElementValues(testTypeElement, TestAnnotation.class); @@ -100,7 +103,7 @@ void testVisitString() { @Test void testVisitType() { - testVisit("type", "\"type\":\"io.microsphere.annotation.processor.GenericTestService\""); + testVisit("type", "\"type\":\"io.microsphere.test.service.GenericTestService\""); } @Test diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/util/JSONElementVisitorTest.java b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/JSONElementVisitorTest.java similarity index 93% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/util/JSONElementVisitorTest.java rename to microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/JSONElementVisitorTest.java index 81a9a5adf..f9c20e905 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/util/JSONElementVisitorTest.java +++ b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/JSONElementVisitorTest.java @@ -15,13 +15,12 @@ * limitations under the License. */ -package io.microsphere.annotation.processor.model.util; +package io.microsphere.lang.model.util; -import io.microsphere.annotation.processor.AbstractAnnotationProcessingTest; -import io.microsphere.annotation.processor.TestAnnotation; -import io.microsphere.annotation.processor.model.Color; -import io.microsphere.annotation.processor.model.StringArrayList; +import io.microsphere.test.annotation.TestAnnotation; +import io.microsphere.test.model.Color; +import io.microsphere.test.model.StringArrayList; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -35,7 +34,7 @@ import java.io.Serializable; import java.util.List; -import static io.microsphere.annotation.processor.util.TypeUtils.ofTypeElement; +import static io.microsphere.lang.model.util.TypeUtils.ofTypeElement; import static java.lang.Boolean.TRUE; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -48,7 +47,7 @@ * @see JSONElementVisitor * @since 1.0.0 */ -class JSONElementVisitorTest extends AbstractAnnotationProcessingTest { +class JSONElementVisitorTest extends UtilTest { private boolean supported; @@ -141,14 +140,14 @@ public Boolean visitTypeAsAnnotationType(TypeElement e, StringBuilder stringBuil @Test void testVisitPackage() { - assertTrue(visitor.visitPackage(this.elements.getPackageElement("io.microsphere.annotation.processor.model.util"), jsonBuilder)); + assertTrue(visitor.visitPackage(this.elements.getPackageElement("io.microsphere.lang.model.util"), jsonBuilder)); assertJson("visitPackage"); } @Test - void testVisitVariableOnUnsupported() { + void testVisitPackageOnUnsupported() { supported = false; - assertFalse(visitor.visitVariable(null, jsonBuilder)); + assertFalse(visitor.visitPackage(this.elements.getPackageElement("io.microsphere.lang.model.util"), jsonBuilder)); } @Test @@ -156,7 +155,6 @@ void testVisitVariableAsEnumConstant() { VariableElement element = getField(Color.class, "RED"); assertTrue(visitor.visitVariable(element, jsonBuilder)); assertJson("visitVariableAsEnumConstant"); - } @Test @@ -176,9 +174,9 @@ void testVisitVariableAsParameter() { } @Test - void testVisitExecutableOnUnsupported() { + void testVisitVariableOnUnsupported() { supported = false; - assertFalse(visitor.visitExecutable(null, jsonBuilder)); + assertFalse(visitor.visitVariable(null, jsonBuilder)); } @Test @@ -196,10 +194,9 @@ void testVisitExecutableAsMethod() { } @Test - void testVisitTypeOnUnsupported() { + void testVisitExecutableOnUnsupported() { supported = false; - TypeElement typeElement = getTypeElement(Serializable.class); - assertFalse(visitor.visitType(typeElement, jsonBuilder)); + assertFalse(visitor.visitExecutable(null, jsonBuilder)); } @Test @@ -231,9 +228,10 @@ void testVisitTypeAsAnnotationType() { } @Test - void testVisitTypeParameterOnUnsupported() { + void testVisitTypeOnUnsupported() { supported = false; - assertFalse(visitor.visitTypeParameter(null, jsonBuilder)); + TypeElement typeElement = getTypeElement(Serializable.class); + assertFalse(visitor.visitType(typeElement, jsonBuilder)); } @Test @@ -248,6 +246,12 @@ void testVisitTypeParameter() { } } + @Test + void testVisitTypeParameterOnUnsupported() { + supported = false; + assertFalse(visitor.visitTypeParameter(null, jsonBuilder)); + } + void assertJson(String expected) { assertEquals(expected, jsonBuilder.toString()); } diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/LoggerUtilsTest.java b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/LoggerUtilsTest.java similarity index 78% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/LoggerUtilsTest.java rename to microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/LoggerUtilsTest.java index dd436fae9..7f916931b 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/LoggerUtilsTest.java +++ b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/LoggerUtilsTest.java @@ -14,16 +14,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor.util; +package io.microsphere.lang.model.util; import org.junit.jupiter.api.Test; -import static io.microsphere.annotation.processor.util.LoggerUtils.LOGGER; -import static io.microsphere.annotation.processor.util.LoggerUtils.debug; -import static io.microsphere.annotation.processor.util.LoggerUtils.error; -import static io.microsphere.annotation.processor.util.LoggerUtils.info; -import static io.microsphere.annotation.processor.util.LoggerUtils.trace; -import static io.microsphere.annotation.processor.util.LoggerUtils.warn; +import static io.microsphere.lang.model.util.LoggerUtils.LOGGER; +import static io.microsphere.lang.model.util.LoggerUtils.debug; +import static io.microsphere.lang.model.util.LoggerUtils.error; +import static io.microsphere.lang.model.util.LoggerUtils.info; +import static io.microsphere.lang.model.util.LoggerUtils.trace; +import static io.microsphere.lang.model.util.LoggerUtils.warn; import static org.junit.jupiter.api.Assertions.assertNotNull; /** diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/MemberUtilsTest.java b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/MemberUtilsTest.java similarity index 92% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/MemberUtilsTest.java rename to microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/MemberUtilsTest.java index aa455d3a5..bae09a873 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/MemberUtilsTest.java +++ b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/MemberUtilsTest.java @@ -14,10 +14,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor.util; +package io.microsphere.lang.model.util; -import io.microsphere.annotation.processor.AbstractAnnotationProcessingTest; -import io.microsphere.annotation.processor.model.Model; +import io.microsphere.test.model.Model; import org.junit.jupiter.api.Test; import javax.lang.model.element.Element; @@ -25,12 +24,12 @@ import javax.lang.model.element.VariableElement; import java.util.List; -import static io.microsphere.annotation.processor.util.MemberUtils.findAllDeclaredMembers; -import static io.microsphere.annotation.processor.util.MemberUtils.findDeclaredMembers; -import static io.microsphere.annotation.processor.util.MemberUtils.getAllDeclaredMembers; -import static io.microsphere.annotation.processor.util.MemberUtils.getDeclaredMembers; import static io.microsphere.lang.function.Predicates.alwaysFalse; import static io.microsphere.lang.function.Predicates.alwaysTrue; +import static io.microsphere.lang.model.util.MemberUtils.findAllDeclaredMembers; +import static io.microsphere.lang.model.util.MemberUtils.findDeclaredMembers; +import static io.microsphere.lang.model.util.MemberUtils.getAllDeclaredMembers; +import static io.microsphere.lang.model.util.MemberUtils.getDeclaredMembers; import static javax.lang.model.util.ElementFilter.fieldsIn; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -40,7 +39,7 @@ * @author Mercy * @since 1.0.0 */ -class MemberUtilsTest extends AbstractAnnotationProcessingTest { +class MemberUtilsTest extends UtilTest { @Test void testGetDeclaredMembers() { diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/MessagerUtilsTest.java b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/MessagerUtilsTest.java similarity index 73% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/MessagerUtilsTest.java rename to microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/MessagerUtilsTest.java index 9e7d629ae..554d4b4d2 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/MessagerUtilsTest.java +++ b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/MessagerUtilsTest.java @@ -15,19 +15,21 @@ * limitations under the License. */ -package io.microsphere.annotation.processor.util; +package io.microsphere.lang.model.util; -import io.microsphere.annotation.processor.AbstractAnnotationProcessingTest; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ReflectiveInvocationContext; import javax.annotation.processing.Messager; +import java.lang.reflect.Method; -import static io.microsphere.annotation.processor.util.MessagerUtils.printError; -import static io.microsphere.annotation.processor.util.MessagerUtils.printMandatoryWarning; -import static io.microsphere.annotation.processor.util.MessagerUtils.printMessage; -import static io.microsphere.annotation.processor.util.MessagerUtils.printNote; -import static io.microsphere.annotation.processor.util.MessagerUtils.printWarning; +import static io.microsphere.lang.model.util.MessagerUtils.printError; +import static io.microsphere.lang.model.util.MessagerUtils.printMandatoryWarning; +import static io.microsphere.lang.model.util.MessagerUtils.printMessage; +import static io.microsphere.lang.model.util.MessagerUtils.printNote; +import static io.microsphere.lang.model.util.MessagerUtils.printWarning; import static javax.tools.Diagnostic.Kind.OTHER; /** @@ -38,12 +40,13 @@ * @see Messager * @since 1.0.0 */ -class MessagerUtilsTest extends AbstractAnnotationProcessingTest { +class MessagerUtilsTest extends UtilTest { private Messager messager; @Override - protected void beforeTest() { + protected void beforeTest(ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) { + super.beforeTest(invocationContext,extensionContext); this.messager = this.processingEnv.getMessager(); } diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/MethodUtilsTest.java b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/MethodUtilsTest.java similarity index 90% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/MethodUtilsTest.java rename to microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/MethodUtilsTest.java index f5e728b85..67a87679d 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/MethodUtilsTest.java +++ b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/MethodUtilsTest.java @@ -14,45 +14,47 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor.util; +package io.microsphere.lang.model.util; -import io.microsphere.annotation.processor.AbstractAnnotationProcessingTest; -import io.microsphere.annotation.processor.TestService; -import io.microsphere.annotation.processor.model.Model; import io.microsphere.constants.Constants; import io.microsphere.constants.PropertyConstants; +import io.microsphere.test.model.Model; +import io.microsphere.test.service.TestService; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ReflectiveInvocationContext; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; import javax.lang.model.type.TypeMirror; import java.io.Serializable; +import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.List; import java.util.Set; -import static io.microsphere.annotation.processor.util.ElementUtils.isPublicNonStatic; -import static io.microsphere.annotation.processor.util.MemberUtils.getDeclaredMembers; -import static io.microsphere.annotation.processor.util.MethodUtils.filterMethods; -import static io.microsphere.annotation.processor.util.MethodUtils.findAllDeclaredMethods; -import static io.microsphere.annotation.processor.util.MethodUtils.findDeclaredMethods; -import static io.microsphere.annotation.processor.util.MethodUtils.findMethod; -import static io.microsphere.annotation.processor.util.MethodUtils.findPublicNonStaticMethods; -import static io.microsphere.annotation.processor.util.MethodUtils.getAllDeclaredMethods; -import static io.microsphere.annotation.processor.util.MethodUtils.getDeclaredMethods; -import static io.microsphere.annotation.processor.util.MethodUtils.getEnclosingElement; -import static io.microsphere.annotation.processor.util.MethodUtils.getMethodName; -import static io.microsphere.annotation.processor.util.MethodUtils.getMethodParameterTypeMirrors; -import static io.microsphere.annotation.processor.util.MethodUtils.getMethodParameterTypeNames; -import static io.microsphere.annotation.processor.util.MethodUtils.getOverrideMethod; -import static io.microsphere.annotation.processor.util.MethodUtils.getReturnTypeName; -import static io.microsphere.annotation.processor.util.MethodUtils.isMethod; -import static io.microsphere.annotation.processor.util.MethodUtils.isPublicNonStaticMethod; -import static io.microsphere.annotation.processor.util.MethodUtils.matches; import static io.microsphere.collection.Lists.ofList; import static io.microsphere.lang.function.Predicates.alwaysFalse; import static io.microsphere.lang.function.Predicates.alwaysTrue; +import static io.microsphere.lang.model.util.ElementUtils.isPublicNonStatic; +import static io.microsphere.lang.model.util.MemberUtils.getDeclaredMembers; +import static io.microsphere.lang.model.util.MethodUtils.filterMethods; +import static io.microsphere.lang.model.util.MethodUtils.findAllDeclaredMethods; +import static io.microsphere.lang.model.util.MethodUtils.findDeclaredMethods; +import static io.microsphere.lang.model.util.MethodUtils.findMethod; +import static io.microsphere.lang.model.util.MethodUtils.findPublicNonStaticMethods; +import static io.microsphere.lang.model.util.MethodUtils.getAllDeclaredMethods; +import static io.microsphere.lang.model.util.MethodUtils.getDeclaredMethods; +import static io.microsphere.lang.model.util.MethodUtils.getEnclosingElement; +import static io.microsphere.lang.model.util.MethodUtils.getMethodName; +import static io.microsphere.lang.model.util.MethodUtils.getMethodParameterTypeMirrors; +import static io.microsphere.lang.model.util.MethodUtils.getMethodParameterTypeNames; +import static io.microsphere.lang.model.util.MethodUtils.getOverrideMethod; +import static io.microsphere.lang.model.util.MethodUtils.getReturnTypeName; +import static io.microsphere.lang.model.util.MethodUtils.isMethod; +import static io.microsphere.lang.model.util.MethodUtils.isPublicNonStaticMethod; +import static io.microsphere.lang.model.util.MethodUtils.matches; import static io.microsphere.reflect.TypeUtils.getTypeNames; import static io.microsphere.util.ArrayUtils.EMPTY_STRING_ARRAY; import static io.microsphere.util.ArrayUtils.ofArray; @@ -71,7 +73,7 @@ * @author Mercy * @since 1.0.0 */ -class MethodUtilsTest extends AbstractAnnotationProcessingTest { +class MethodUtilsTest extends UtilTest { private List objectMethods; @@ -83,8 +85,8 @@ protected void addCompiledClasses(Set> compiledClasses) { } @Override - protected void beforeTest() { - super.beforeTest(); + protected void beforeTest(ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) { + super.beforeTest(invocationContext,extensionContext); TypeElement type = getTypeElement(Object.class); List methods = getDeclaredMethods(type); this.objectMethods = methods; diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/util/ResolvableAnnotationValueVisitorTest.java b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/ResolvableAnnotationValueVisitorTest.java similarity index 78% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/util/ResolvableAnnotationValueVisitorTest.java rename to microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/ResolvableAnnotationValueVisitorTest.java index 0f0ef36d7..3189ce3f9 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/model/util/ResolvableAnnotationValueVisitorTest.java +++ b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/ResolvableAnnotationValueVisitorTest.java @@ -15,24 +15,26 @@ * limitations under the License. */ -package io.microsphere.annotation.processor.model.util; +package io.microsphere.lang.model.util; -import io.microsphere.annotation.processor.AbstractAnnotationProcessingTest; -import io.microsphere.annotation.processor.GenericTestService; -import io.microsphere.annotation.processor.TestAnnotation; -import io.microsphere.annotation.processor.TestService; +import io.microsphere.test.annotation.TestAnnotation; +import io.microsphere.test.service.GenericTestService; +import io.microsphere.test.service.TestService; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ReflectiveInvocationContext; import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.AnnotationValueVisitor; import javax.lang.model.element.ExecutableElement; import java.io.Serializable; +import java.lang.reflect.Method; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; -import static io.microsphere.annotation.processor.util.AnnotationUtils.getElementValue; -import static io.microsphere.annotation.processor.util.AnnotationUtils.getElementValues; +import static io.microsphere.lang.model.util.AnnotationUtils.getElementValue; +import static io.microsphere.lang.model.util.AnnotationUtils.getElementValues; import static java.util.Objects.deepEquals; import static java.util.concurrent.TimeUnit.HOURS; import static java.util.stream.Stream.of; @@ -47,7 +49,7 @@ * @see ResolvableAnnotationValueVisitor * @since 1.0.0 */ -class ResolvableAnnotationValueVisitorTest extends AbstractAnnotationProcessingTest { +class ResolvableAnnotationValueVisitorTest extends UtilTest { private ResolvableAnnotationValueVisitor visitor; @@ -79,17 +81,18 @@ class ResolvableAnnotationValueVisitorTest extends AbstractAnnotationProcessingT private Map testAnnotationAttributes; - protected void beforeTest() { - super.beforeTest(); + @Override + protected void beforeTest(ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) { + super.beforeTest(invocationContext, extensionContext); this.visitor = new ResolvableAnnotationValueVisitor(); this.visitor1 = new ResolvableAnnotationValueVisitor(true); this.visitor2 = new ResolvableAnnotationValueVisitor(true, true); - this.testAnnotationAttributes = getElementValues(testTypeElement, TestAnnotation.class); + this.testAnnotationAttributes = getElementValues(this.testTypeElement, TestAnnotation.class); } @Test void testVisitBoolean() { - assertEquals(BOOLEAN_VALUE, visitor.visitBoolean(BOOLEAN_VALUE, null)); + assertEquals(BOOLEAN_VALUE, this.visitor.visitBoolean(BOOLEAN_VALUE, null)); assertVisit(this.visitor, "z", BOOLEAN_VALUE); assertVisit(this.visitor1, "z", BOOLEAN_VALUE); assertVisit(this.visitor2, "z", BOOLEAN_VALUE); @@ -97,7 +100,7 @@ void testVisitBoolean() { @Test void testVisitByte() { - assertEquals(BYTE_VALUE, visitor.visitByte(BYTE_VALUE, null)); + assertEquals(BYTE_VALUE, this.visitor.visitByte(BYTE_VALUE, null)); assertVisit(this.visitor, "b", BYTE_VALUE); assertVisit(this.visitor1, "b", BYTE_VALUE); assertVisit(this.visitor2, "b", BYTE_VALUE); @@ -105,7 +108,7 @@ void testVisitByte() { @Test void testVisitChar() { - assertEquals(CHAR_VALUE, visitor.visitChar(CHAR_VALUE, null)); + assertEquals(CHAR_VALUE, this.visitor.visitChar(CHAR_VALUE, null)); assertVisit(this.visitor, "c", CHAR_VALUE); assertVisit(this.visitor1, "c", CHAR_VALUE); assertVisit(this.visitor2, "c", CHAR_VALUE); @@ -113,7 +116,7 @@ void testVisitChar() { @Test void testVisitDouble() { - assertEquals(DOUBLE_VALUE, visitor.visitDouble(DOUBLE_VALUE, null)); + assertEquals(DOUBLE_VALUE, this.visitor.visitDouble(DOUBLE_VALUE, null)); assertVisit(this.visitor, "d", DOUBLE_VALUE); assertVisit(this.visitor1, "d", DOUBLE_VALUE); assertVisit(this.visitor2, "d", DOUBLE_VALUE); @@ -121,7 +124,7 @@ void testVisitDouble() { @Test void testVisitFloat() { - assertEquals(FLOAT_VALUE, visitor.visitFloat(FLOAT_VALUE, null)); + assertEquals(FLOAT_VALUE, this.visitor.visitFloat(FLOAT_VALUE, null)); assertVisit(this.visitor, "f", FLOAT_VALUE); assertVisit(this.visitor1, "f", FLOAT_VALUE); assertVisit(this.visitor2, "f", FLOAT_VALUE); @@ -129,7 +132,7 @@ void testVisitFloat() { @Test void testVisitInt() { - assertEquals(INT_VALUE, visitor.visitInt(INT_VALUE, null)); + assertEquals(INT_VALUE, this.visitor.visitInt(INT_VALUE, null)); assertVisit(this.visitor, "i", INT_VALUE); assertVisit(this.visitor1, "i", INT_VALUE); assertVisit(this.visitor2, "i", INT_VALUE); @@ -137,7 +140,7 @@ void testVisitInt() { @Test void testVisitLong() { - assertEquals(LONG_VALUE, visitor.visitLong(LONG_VALUE, null)); + assertEquals(LONG_VALUE, this.visitor.visitLong(LONG_VALUE, null)); assertVisit(this.visitor, "l", LONG_VALUE); assertVisit(this.visitor1, "l", LONG_VALUE); assertVisit(this.visitor2, "l", LONG_VALUE); @@ -145,7 +148,7 @@ void testVisitLong() { @Test void testVisitShort() { - assertEquals(SHORT_VALUE, visitor.visitShort(SHORT_VALUE, null)); + assertEquals(SHORT_VALUE, this.visitor.visitShort(SHORT_VALUE, null)); assertVisit(this.visitor, "s", SHORT_VALUE); assertVisit(this.visitor1, "s", SHORT_VALUE); assertVisit(this.visitor2, "s", SHORT_VALUE); @@ -153,15 +156,15 @@ void testVisitShort() { @Test void testVisitString() { - assertEquals(STRING_VALUE, visitor.visitString(STRING_VALUE, null)); + assertEquals(STRING_VALUE, this.visitor.visitString(STRING_VALUE, null)); assertVisit(this.visitor, "string", STRING_VALUE); assertVisit(this.visitor1, "string", STRING_VALUE); - assertVisit(this.visitor1, "string", STRING_VALUE); + assertVisit(this.visitor2, "string", STRING_VALUE); } @Test void testVisitType() { - assertEquals(TYPE_VALUE, visitor.visitType(getTypeMirror(TYPE_VALUE), null)); + assertEquals(TYPE_VALUE, this.visitor.visitType(getTypeMirror(TYPE_VALUE), null)); assertVisit(this.visitor, "type", TYPE_VALUE); assertVisit(this.visitor1, "type", TYPE_VALUE.getName()); assertVisit(this.visitor2, "type", TYPE_VALUE.getName()); @@ -201,7 +204,7 @@ void testVisitUnknown() { for (Entry elementValue : this.testAnnotationAttributes.entrySet()) { ExecutableElement attributeMethod = elementValue.getKey(); AnnotationValue annotationValue = elementValue.getValue(); - assertSame(annotationValue, visitor.visitUnknown(annotationValue, attributeMethod)); + assertSame(annotationValue, this.visitor.visitUnknown(annotationValue, attributeMethod)); } } diff --git a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/TypeUtilsTest.java b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/TypeUtilsTest.java similarity index 94% rename from microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/TypeUtilsTest.java rename to microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/TypeUtilsTest.java index 3908724fc..9e73f8b5c 100644 --- a/microsphere-annotation-processor/src/test/java/io/microsphere/annotation/processor/util/TypeUtilsTest.java +++ b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/TypeUtilsTest.java @@ -14,19 +14,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.microsphere.annotation.processor.util; - -import io.microsphere.annotation.processor.AbstractAnnotationProcessingTest; -import io.microsphere.annotation.processor.DefaultTestService; -import io.microsphere.annotation.processor.GenericTestService; -import io.microsphere.annotation.processor.TestService; -import io.microsphere.annotation.processor.TestServiceImpl; -import io.microsphere.annotation.processor.model.ArrayTypeModel; -import io.microsphere.annotation.processor.model.CollectionTypeModel; -import io.microsphere.annotation.processor.model.Color; -import io.microsphere.annotation.processor.model.MapTypeModel; -import io.microsphere.annotation.processor.model.Model; -import io.microsphere.annotation.processor.model.PrimitiveTypeModel; +package io.microsphere.lang.model.util; + +import io.microsphere.test.model.ArrayTypeModel; +import io.microsphere.test.model.CollectionTypeModel; +import io.microsphere.test.model.Color; +import io.microsphere.test.model.MapTypeModel; +import io.microsphere.test.model.Model; +import io.microsphere.test.model.PrimitiveTypeModel; +import io.microsphere.test.service.DefaultTestService; +import io.microsphere.test.service.GenericTestService; +import io.microsphere.test.service.TestService; +import io.microsphere.test.service.TestServiceImpl; import org.junit.jupiter.api.Test; import javax.lang.model.element.Element; @@ -45,56 +44,56 @@ import java.util.concurrent.TimeUnit; import java.util.function.Predicate; -import static io.microsphere.annotation.processor.util.FieldUtils.findField; -import static io.microsphere.annotation.processor.util.FieldUtils.getDeclaredFields; -import static io.microsphere.annotation.processor.util.MethodUtils.findMethod; -import static io.microsphere.annotation.processor.util.TypeUtils.findAllDeclaredTypes; -import static io.microsphere.annotation.processor.util.TypeUtils.findAllDeclaredTypesOfInterfaces; -import static io.microsphere.annotation.processor.util.TypeUtils.findAllDeclaredTypesOfSuperTypes; -import static io.microsphere.annotation.processor.util.TypeUtils.findAllDeclaredTypesOfSuperclasses; -import static io.microsphere.annotation.processor.util.TypeUtils.findAllTypeElementsOfInterfaces; -import static io.microsphere.annotation.processor.util.TypeUtils.findAllTypeElementsOfSuperclasses; -import static io.microsphere.annotation.processor.util.TypeUtils.findAllTypeMirrorsOfInterfaces; -import static io.microsphere.annotation.processor.util.TypeUtils.findDeclaredTypes; -import static io.microsphere.annotation.processor.util.TypeUtils.findDeclaredTypesOfInterfaces; -import static io.microsphere.annotation.processor.util.TypeUtils.findInterfaceTypeMirror; -import static io.microsphere.annotation.processor.util.TypeUtils.findTypeElements; -import static io.microsphere.annotation.processor.util.TypeUtils.findTypeElementsOfInterfaces; -import static io.microsphere.annotation.processor.util.TypeUtils.findTypeMirrorsOfInterfaces; -import static io.microsphere.annotation.processor.util.TypeUtils.getAllDeclaredTypes; -import static io.microsphere.annotation.processor.util.TypeUtils.getAllDeclaredTypesOfInterfaces; -import static io.microsphere.annotation.processor.util.TypeUtils.getAllDeclaredTypesOfSuperTypes; -import static io.microsphere.annotation.processor.util.TypeUtils.getAllDeclaredTypesOfSuperclasses; -import static io.microsphere.annotation.processor.util.TypeUtils.getAllTypeElements; -import static io.microsphere.annotation.processor.util.TypeUtils.getAllTypeElementsOfInterfaces; -import static io.microsphere.annotation.processor.util.TypeUtils.getAllTypeElementsOfSuperTypes; -import static io.microsphere.annotation.processor.util.TypeUtils.getAllTypeElementsOfSuperclasses; -import static io.microsphere.annotation.processor.util.TypeUtils.getAllTypeMirrorsOfInterfaces; -import static io.microsphere.annotation.processor.util.TypeUtils.getDeclaredTypeOfSuperclass; -import static io.microsphere.annotation.processor.util.TypeUtils.getDeclaredTypes; -import static io.microsphere.annotation.processor.util.TypeUtils.getDeclaredTypesOfInterfaces; -import static io.microsphere.annotation.processor.util.TypeUtils.getTypeElementOfSuperclass; -import static io.microsphere.annotation.processor.util.TypeUtils.getTypeElementsOfInterfaces; -import static io.microsphere.annotation.processor.util.TypeUtils.getTypeMirrorsOfInterfaces; -import static io.microsphere.annotation.processor.util.TypeUtils.isAnnotationType; -import static io.microsphere.annotation.processor.util.TypeUtils.isArrayType; -import static io.microsphere.annotation.processor.util.TypeUtils.isClassType; -import static io.microsphere.annotation.processor.util.TypeUtils.isDeclaredType; -import static io.microsphere.annotation.processor.util.TypeUtils.isEnumType; -import static io.microsphere.annotation.processor.util.TypeUtils.isInterfaceType; -import static io.microsphere.annotation.processor.util.TypeUtils.isPrimitiveType; -import static io.microsphere.annotation.processor.util.TypeUtils.isSameType; -import static io.microsphere.annotation.processor.util.TypeUtils.isSimpleType; -import static io.microsphere.annotation.processor.util.TypeUtils.isTypeElement; -import static io.microsphere.annotation.processor.util.TypeUtils.ofDeclaredType; -import static io.microsphere.annotation.processor.util.TypeUtils.ofDeclaredTypes; -import static io.microsphere.annotation.processor.util.TypeUtils.ofTypeElement; -import static io.microsphere.annotation.processor.util.TypeUtils.ofTypeElements; -import static io.microsphere.annotation.processor.util.TypeUtils.ofTypeMirrors; -import static io.microsphere.annotation.processor.util.TypeUtils.typeElementFinder; import static io.microsphere.collection.ListUtils.ofList; import static io.microsphere.lang.function.Predicates.alwaysFalse; import static io.microsphere.lang.function.Predicates.alwaysTrue; +import static io.microsphere.lang.model.util.FieldUtils.findField; +import static io.microsphere.lang.model.util.FieldUtils.getDeclaredFields; +import static io.microsphere.lang.model.util.MethodUtils.findMethod; +import static io.microsphere.lang.model.util.TypeUtils.findAllDeclaredTypes; +import static io.microsphere.lang.model.util.TypeUtils.findAllDeclaredTypesOfInterfaces; +import static io.microsphere.lang.model.util.TypeUtils.findAllDeclaredTypesOfSuperTypes; +import static io.microsphere.lang.model.util.TypeUtils.findAllDeclaredTypesOfSuperclasses; +import static io.microsphere.lang.model.util.TypeUtils.findAllTypeElementsOfInterfaces; +import static io.microsphere.lang.model.util.TypeUtils.findAllTypeElementsOfSuperclasses; +import static io.microsphere.lang.model.util.TypeUtils.findAllTypeMirrorsOfInterfaces; +import static io.microsphere.lang.model.util.TypeUtils.findDeclaredTypes; +import static io.microsphere.lang.model.util.TypeUtils.findDeclaredTypesOfInterfaces; +import static io.microsphere.lang.model.util.TypeUtils.findInterfaceTypeMirror; +import static io.microsphere.lang.model.util.TypeUtils.findTypeElements; +import static io.microsphere.lang.model.util.TypeUtils.findTypeElementsOfInterfaces; +import static io.microsphere.lang.model.util.TypeUtils.findTypeMirrorsOfInterfaces; +import static io.microsphere.lang.model.util.TypeUtils.getAllDeclaredTypes; +import static io.microsphere.lang.model.util.TypeUtils.getAllDeclaredTypesOfInterfaces; +import static io.microsphere.lang.model.util.TypeUtils.getAllDeclaredTypesOfSuperTypes; +import static io.microsphere.lang.model.util.TypeUtils.getAllDeclaredTypesOfSuperclasses; +import static io.microsphere.lang.model.util.TypeUtils.getAllTypeElements; +import static io.microsphere.lang.model.util.TypeUtils.getAllTypeElementsOfInterfaces; +import static io.microsphere.lang.model.util.TypeUtils.getAllTypeElementsOfSuperTypes; +import static io.microsphere.lang.model.util.TypeUtils.getAllTypeElementsOfSuperclasses; +import static io.microsphere.lang.model.util.TypeUtils.getAllTypeMirrorsOfInterfaces; +import static io.microsphere.lang.model.util.TypeUtils.getDeclaredTypeOfSuperclass; +import static io.microsphere.lang.model.util.TypeUtils.getDeclaredTypes; +import static io.microsphere.lang.model.util.TypeUtils.getDeclaredTypesOfInterfaces; +import static io.microsphere.lang.model.util.TypeUtils.getTypeElementOfSuperclass; +import static io.microsphere.lang.model.util.TypeUtils.getTypeElementsOfInterfaces; +import static io.microsphere.lang.model.util.TypeUtils.getTypeMirrorsOfInterfaces; +import static io.microsphere.lang.model.util.TypeUtils.isAnnotationType; +import static io.microsphere.lang.model.util.TypeUtils.isArrayType; +import static io.microsphere.lang.model.util.TypeUtils.isClassType; +import static io.microsphere.lang.model.util.TypeUtils.isDeclaredType; +import static io.microsphere.lang.model.util.TypeUtils.isEnumType; +import static io.microsphere.lang.model.util.TypeUtils.isInterfaceType; +import static io.microsphere.lang.model.util.TypeUtils.isPrimitiveType; +import static io.microsphere.lang.model.util.TypeUtils.isSameType; +import static io.microsphere.lang.model.util.TypeUtils.isSimpleType; +import static io.microsphere.lang.model.util.TypeUtils.isTypeElement; +import static io.microsphere.lang.model.util.TypeUtils.ofDeclaredType; +import static io.microsphere.lang.model.util.TypeUtils.ofDeclaredTypes; +import static io.microsphere.lang.model.util.TypeUtils.ofTypeElement; +import static io.microsphere.lang.model.util.TypeUtils.ofTypeElements; +import static io.microsphere.lang.model.util.TypeUtils.ofTypeMirrors; +import static io.microsphere.lang.model.util.TypeUtils.typeElementFinder; import static io.microsphere.reflect.TypeUtils.getTypeNames; import static io.microsphere.util.ArrayUtils.EMPTY_STRING_ARRAY; import static io.microsphere.util.ArrayUtils.combine; @@ -114,7 +113,7 @@ * @author Mercy * @since 1.0.0 */ -class TypeUtilsTest extends AbstractAnnotationProcessingTest { +class TypeUtilsTest extends UtilTest { /** * self type diff --git a/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/UtilTest.java b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/UtilTest.java new file mode 100644 index 000000000..2730dab41 --- /dev/null +++ b/microsphere-lang-model/src/test/java/io/microsphere/lang/model/util/UtilTest.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.microsphere.lang.model.util; + +import io.microsphere.test.annotation.processing.AbstractAnnotationProcessingTest; +import io.microsphere.test.service.TestServiceImpl; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ReflectiveInvocationContext; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeMirror; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.List; + +import static io.microsphere.lang.model.util.ConstructorUtils.findConstructor; +import static io.microsphere.lang.model.util.FieldUtils.findField; +import static io.microsphere.lang.model.util.MethodUtils.findMethod; +import static java.util.Collections.emptyList; +import static org.junit.jupiter.api.Assertions.assertSame; + +/** + * The utilies class for testing + * + * @author Mercy + * @see AbstractAnnotationProcessingTest + * @since 1.0.0 + */ +public abstract class UtilTest extends AbstractAnnotationProcessingTest { + + @Override + protected void beforeTest(ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext) { + initTestClass(TestServiceImpl.class); + } + + protected List getTypeMirrors(Type... types) { + return TypeUtils.getTypeMirrors(processingEnv, types); + } + + protected TypeMirror getTypeMirror(Type type) { + return TypeUtils.getTypeMirror(processingEnv, type); + } + + protected List getTypeElements(Type... types) { + return TypeUtils.getTypeElements(processingEnv, types); + } + + protected TypeElement getTypeElement(Type type) { + return TypeUtils.getTypeElement(processingEnv, type); + } + + protected VariableElement getField(Type type, String fieldName) { + TypeElement typeElement = getTypeElement(type); + return findField(typeElement, fieldName); + } + + protected ExecutableElement getMethod(Type type, String methodName, Type... parameterTypes) { + TypeElement typeElement = getTypeElement(type); + return findMethod(typeElement, methodName, parameterTypes); + } + + protected ExecutableElement getConstructor(Type type, Type... parameterTypes) { + TypeElement typeElement = getTypeElement(type); + return findConstructor(typeElement, parameterTypes); + } + + protected Element[] getElements(Type... types) { + return getTypeMirrors(types).stream().map(TypeUtils::ofTypeElement).toArray(Element[]::new); + } + + protected DeclaredType getDeclaredType(Type type) { + return TypeUtils.getDeclaredType(processingEnv, type); + } + + protected void assertEmptyList(List list) { + assertSame(emptyList(), list); + } +} diff --git a/mvnw b/mvnw index 8a8fb2282..bd8896bf2 100755 --- a/mvnw +++ b/mvnw @@ -8,7 +8,7 @@ # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # -# https://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an @@ -19,298 +19,277 @@ # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- -# Maven Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir +# Apache Maven Wrapper startup batch script, version 3.3.4 # # Optional ENV vars # ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# JAVA_HOME - location of a JDK home dir, required when download maven via java source +# MVNW_REPOURL - repo url base for downloading maven distribution +# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output # ---------------------------------------------------------------------------- -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /usr/local/etc/mavenrc ] ; then - . /usr/local/etc/mavenrc - fi - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi +set -euf +[ "${MVNW_VERBOSE-}" != debug ] || set -x - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi +# OS specific support. +native_path() { printf %s\\n "$1"; } +case "$(uname)" in +CYGWIN* | MINGW*) + [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" + native_path() { cygpath --path --windows "$1"; } + ;; +esac -fi +# set JAVACMD and JAVACCMD +set_java_home() { + # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched + if [ -n "${JAVA_HOME-}" ]; then + if [ -x "$JAVA_HOME/jre/sh/java" ]; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACCMD="$JAVA_HOME/jre/sh/javac" + else + JAVACMD="$JAVA_HOME/bin/java" + JAVACCMD="$JAVA_HOME/bin/javac" -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" + if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then + echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 + echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 + return 1 fi fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` + else + JAVACMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v java + )" || : + JAVACCMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v javac + )" || : + + if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then + echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 + return 1 + fi fi -fi - -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" +} - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi +# hash string like Java String::hashCode +hash_string() { + str="${1:-}" h=0 + while [ -n "$str" ]; do + char="${str%"${str#?}"}" + h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) + str="${str#?}" done + printf %x\\n $h +} - saveddir=`pwd` +verbose() { :; } +[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } - M2_HOME=`dirname "$PRG"`/.. +die() { + printf %s\\n "$1" >&2 + exit 1 +} - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi +scriptDir="$(dirname "$0")" +scriptName="$(basename "$0")" + +# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties +while IFS="=" read -r key value; do + case "${key-}" in + distributionUrl) distributionUrl=$(trim "${value-}") ;; + distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; + esac +done <"$scriptDir/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" + +case "${distributionUrl##*/}" in +maven-mvnd-*bin.*) + MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ + case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in + *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; + :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; + :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; + :Linux*x86_64*) distributionPlatform=linux-amd64 ;; + *) + echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 + distributionPlatform=linux-amd64 + ;; + esac + distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" + ;; +maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; +*) MVN_CMD="mvn${scriptName#mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +esac -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" +distributionUrlName="${distributionUrl##*/}" +distributionUrlNameMain="${distributionUrlName%.*}" +distributionUrlNameMain="${distributionUrlNameMain%-bin}" +MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" +MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" + +exec_maven() { + unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : + exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" +} -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +if [ -d "$MAVEN_HOME" ]; then + verbose "found existing MAVEN_HOME at $MAVEN_HOME" + exec_maven "$@" fi -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi +case "${distributionUrl-}" in +*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; +*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; +esac -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="`\\unset -f command; \\command -v java`" - fi +# prepare tmp dir +if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then + clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } + trap clean HUP INT TERM EXIT +else + die "cannot create temp dir" fi -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi +mkdir -p -- "${MAVEN_HOME%/*}" + +# Download and Install Apache Maven +verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +verbose "Downloading from: $distributionUrl" +verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." +# select .zip or .tar.gz +if ! command -v unzip >/dev/null; then + distributionUrl="${distributionUrl%.zip}.tar.gz" + distributionUrlName="${distributionUrl##*/}" fi -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher +# verbose opt +__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' +[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { +# normalize http auth +case "${MVNW_PASSWORD:+has-password}" in +'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; +has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; +esac - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi +if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then + verbose "Found wget ... using wget" + wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" +elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then + verbose "Found curl ... using curl" + curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" +elif set_java_home; then + verbose "Falling back to use Java to download" + javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" + targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" + cat >"$javaSource" <<-END + public class Downloader extends java.net.Authenticator + { + protected java.net.PasswordAuthentication getPasswordAuthentication() + { + return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); + } + public static void main( String[] args ) throws Exception + { + setDefault( new Downloader() ); + java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); + } + } + END + # For Cygwin/MinGW, switch paths to Windows format before running javac and java + verbose " - Compiling Downloader.java ..." + "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" + verbose " - Running Downloader.java ..." + "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" +fi - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break +# If specified, validate the SHA-256 sum of the Maven distribution zip file +if [ -n "${distributionSha256Sum-}" ]; then + distributionSha256Result=false + if [ "$MVN_CMD" = mvnd.sh ]; then + echo "Checksum validation is not supported for maven-mvnd." >&2 + echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + elif command -v sha256sum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c - >/dev/null 2>&1; then + distributionSha256Result=true fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` + elif command -v shasum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then + distributionSha256Result=true fi - # end of workaround - done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 + echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + fi + if [ $distributionSha256Result = false ]; then + echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 + echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 + exit 1 fi -} - -BASE_DIR=`find_maven_basedir "$(pwd)"` -if [ -z "$BASE_DIR" ]; then - exit 1; fi -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi +# unzip and move +if command -v unzip >/dev/null; then + unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - if [ -n "$MVNW_REPOURL" ]; then - jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - else - jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - fi - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" - if $cygwin; then - wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` - fi + tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" +fi - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - else - wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" - fi - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl -o "$wrapperJarPath" "$jarUrl" -f - else - curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f - fi +# Find the actual extracted directory name (handles snapshots where filename != directory name) +actualDistributionDir="" - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - # For Cygwin, switch paths to Windows format before running javac - if $cygwin; then - javaClass=`cygpath --path --windows "$javaClass"` - fi - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi - fi +# First try the expected directory name (for regular distributions) +if [ -d "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" ]; then + if [ -f "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/bin/$MVN_CMD" ]; then + actualDistributionDir="$distributionUrlNameMain" + fi fi -########################################################################################## -# End of extension -########################################################################################## -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR -fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +# If not found, search for any directory with the Maven executable (for snapshots) +if [ -z "$actualDistributionDir" ]; then + # enable globbing to iterate over items + set +f + for dir in "$TMP_DOWNLOAD_DIR"/*; do + if [ -d "$dir" ]; then + if [ -f "$dir/bin/$MVN_CMD" ]; then + actualDistributionDir="$(basename "$dir")" + break + fi + fi + done + set -f fi -# Provide a "standardized" way to retrieve the CLI args that will -# work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" -export MAVEN_CMD_LINE_ARGS +if [ -z "$actualDistributionDir" ]; then + verbose "Contents of $TMP_DOWNLOAD_DIR:" + verbose "$(ls -la "$TMP_DOWNLOAD_DIR")" + die "Could not find Maven distribution directory in extracted archive" +fi -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain +verbose "Found extracted Maven distribution directory: $actualDistributionDir" +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$actualDistributionDir/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$actualDistributionDir" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" -exec "$JAVACMD" \ - $MAVEN_OPTS \ - $MAVEN_DEBUG_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" \ - "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" +clean || : +exec_maven "$@" diff --git a/mvnw.cmd b/mvnw.cmd index 1d8ab018e..5761d9489 100644 --- a/mvnw.cmd +++ b/mvnw.cmd @@ -1,188 +1,189 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM https://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* -if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - -FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% ^ - %JVM_CONFIG_MAVEN_PROPS% ^ - %MAVEN_OPTS% ^ - %MAVEN_DEBUG_OPTS% ^ - -classpath %WRAPPER_JAR% ^ - "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ - %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" -if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%"=="on" pause - -if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% - -cmd /C exit /B %ERROR_CODE% +<# : batch portion +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.3.4 +@REM +@REM Optional ENV vars +@REM MVNW_REPOURL - repo url base for downloading maven distribution +@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output +@REM ---------------------------------------------------------------------------- + +@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) +@SET __MVNW_CMD__= +@SET __MVNW_ERROR__= +@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% +@SET PSModulePath= +@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( + IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) +) +@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% +@SET __MVNW_PSMODULEP_SAVE= +@SET __MVNW_ARG0_NAME__= +@SET MVNW_USERNAME= +@SET MVNW_PASSWORD= +@IF NOT "%__MVNW_CMD__%"=="" ("%__MVNW_CMD__%" %*) +@echo Cannot start maven from wrapper >&2 && exit /b 1 +@GOTO :EOF +: end batch / begin powershell #> + +$ErrorActionPreference = "Stop" +if ($env:MVNW_VERBOSE -eq "true") { + $VerbosePreference = "Continue" +} + +# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties +$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl +if (!$distributionUrl) { + Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" +} + +switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { + "maven-mvnd-*" { + $USE_MVND = $true + $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" + $MVN_CMD = "mvnd.cmd" + break + } + default { + $USE_MVND = $false + $MVN_CMD = $script -replace '^mvnw','mvn' + break + } +} + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +if ($env:MVNW_REPOURL) { + $MVNW_REPO_PATTERN = if ($USE_MVND -eq $False) { "/org/apache/maven/" } else { "/maven/mvnd/" } + $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace "^.*$MVNW_REPO_PATTERN",'')" +} +$distributionUrlName = $distributionUrl -replace '^.*/','' +$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' + +$MAVEN_M2_PATH = "$HOME/.m2" +if ($env:MAVEN_USER_HOME) { + $MAVEN_M2_PATH = "$env:MAVEN_USER_HOME" +} + +if (-not (Test-Path -Path $MAVEN_M2_PATH)) { + New-Item -Path $MAVEN_M2_PATH -ItemType Directory | Out-Null +} + +$MAVEN_WRAPPER_DISTS = $null +if ((Get-Item $MAVEN_M2_PATH).Target[0] -eq $null) { + $MAVEN_WRAPPER_DISTS = "$MAVEN_M2_PATH/wrapper/dists" +} else { + $MAVEN_WRAPPER_DISTS = (Get-Item $MAVEN_M2_PATH).Target[0] + "/wrapper/dists" +} + +$MAVEN_HOME_PARENT = "$MAVEN_WRAPPER_DISTS/$distributionUrlNameMain" +$MAVEN_HOME_NAME = ([System.Security.Cryptography.SHA256]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' +$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" + +if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { + Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" + Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" + exit $? +} + +if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { + Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" +} + +# prepare tmp dir +$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile +$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" +$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null +trap { + if ($TMP_DOWNLOAD_DIR.Exists) { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } + } +} + +New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null + +# Download and Install Apache Maven +Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +Write-Verbose "Downloading from: $distributionUrl" +Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +$webclient = New-Object System.Net.WebClient +if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { + $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) +} +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum +if ($distributionSha256Sum) { + if ($USE_MVND) { + Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." + } + Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash + if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { + Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." + } +} + +# unzip and move +Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null + +# Find the actual extracted directory name (handles snapshots where filename != directory name) +$actualDistributionDir = "" + +# First try the expected directory name (for regular distributions) +$expectedPath = Join-Path "$TMP_DOWNLOAD_DIR" "$distributionUrlNameMain" +$expectedMvnPath = Join-Path "$expectedPath" "bin/$MVN_CMD" +if ((Test-Path -Path $expectedPath -PathType Container) -and (Test-Path -Path $expectedMvnPath -PathType Leaf)) { + $actualDistributionDir = $distributionUrlNameMain +} + +# If not found, search for any directory with the Maven executable (for snapshots) +if (!$actualDistributionDir) { + Get-ChildItem -Path "$TMP_DOWNLOAD_DIR" -Directory | ForEach-Object { + $testPath = Join-Path $_.FullName "bin/$MVN_CMD" + if (Test-Path -Path $testPath -PathType Leaf) { + $actualDistributionDir = $_.Name + } + } +} + +if (!$actualDistributionDir) { + Write-Error "Could not find Maven distribution directory in extracted archive" +} + +Write-Verbose "Found extracted Maven distribution directory: $actualDistributionDir" +Rename-Item -Path "$TMP_DOWNLOAD_DIR/$actualDistributionDir" -NewName $MAVEN_HOME_NAME | Out-Null +try { + Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null +} catch { + if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { + Write-Error "fail to move MAVEN_HOME" + } +} finally { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } +} + +Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/pom.xml b/pom.xml index 2d4bac37e..dc5c6a270 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ io.github.microsphere-projects microsphere-build - 0.2.2 + 0.2.3 io.github.microsphere-projects @@ -51,14 +51,18 @@ - 0.1.7-SNAPSHOT + 0.1.8-SNAPSHOT microsphere-java-parent microsphere-java-dependencies - microsphere-annotation-processor + microsphere-java-annotations microsphere-java-core + microsphere-jdk-tools + microsphere-java-test + microsphere-lang-model + microsphere-annotation-processor \ No newline at end of file