diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index d3f5f6309..724db0484 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -1,14 +1,18 @@
---
-name: Bug report
-about: Create a report to help us improve
-
+name: π Bug Report
+about: Report a general framework issue. help us improve this framework.
---
-**Describe the bug**
+- System Version (e.g. Mac Os 10.14.3):
+- Build tools (e.g. maven/gradle):
+- JDK Version (e.g. e.g `2.0.8-R1`):
+- Database Version:
+
+### Describe the bug
A clear and concise description of what the bug is.
-**To Reproduce**
+### To Reproduce
Steps to reproduce the behavior:
@@ -17,14 +21,14 @@ Steps to reproduce the behavior:
3. JDK version and blade version(e.g `2.0.8-R1`)
4. See error
-**Expected behavior**
+### Expected behavior:
A clear and concise description of what you expected to happen.
-**Screenshots**
+### Screenshots:
If applicable, add screenshots to help explain your problem.
-**Additional context**
+### Additional context:
Add any other context about the problem here.
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/documentation_issue.md b/.github/ISSUE_TEMPLATE/documentation_issue.md
new file mode 100644
index 000000000..2a56a7d30
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/documentation_issue.md
@@ -0,0 +1,9 @@
+---
+name: π Documentation Issue
+about: For documentation issues, open a pull request at https://github.com/lets-blade/lets-blade.github.io
+
+---
+
+The blade documentation has its own dedicated repository. Please open a pull request at https://github.com/lets-blade/lets-blade.github.io to correct the issue you have found.
+
+Thanks!
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index 65322c2e0..b2c7140d9 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -1,21 +1,21 @@
---
-name: Feature request
-about: Suggest an idea for this project
+name: β¨ Feature Request
+about: For ideas or feature requests
---
-**Is your feature request related to a problem? Please describe.**
+### Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
-**Describe the solution you'd like**
+### Describe the solution you'd like
A clear and concise description of what you want to happen.
-**Describe alternatives you've considered**
+### Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
-**Additional context**
+### Additional context
Add any other context or screenshots about the feature request here.
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/general_question.md b/.github/ISSUE_TEMPLATE/general_question.md
index bc4a2621a..df6ef6322 100644
--- a/.github/ISSUE_TEMPLATE/general_question.md
+++ b/.github/ISSUE_TEMPLATE/general_question.md
@@ -1,5 +1,5 @@
---
-name: General question
+name: π» General Question
about: Template for asking question
---
diff --git a/README.md b/README.md
index d82604e88..efcfd2bc8 100644
--- a/README.md
+++ b/README.md
@@ -65,14 +65,14 @@ Run with `Maven`:
com.bladejava
blade-mvc
- 2.0.15.ALPHA
+ 2.0.15.BETA
```
or `Gradle`:
```sh
-compile 'com.bladejava:blade-mvc:2.0.15.ALPHA'
+compile 'com.bladejava:blade-mvc:2.0.15.BETA'
```
Write the `main` method and the `Hello World`:
diff --git a/README_CN.md b/README_CN.md
index c694aee3e..e90fd8b86 100644
--- a/README_CN.md
+++ b/README_CN.md
@@ -61,7 +61,7 @@
com.bladejava
blade-mvc
- 2.0.15.ALPHA
+ 2.0.15.BETA
```
@@ -70,7 +70,7 @@
ζθ
`Gradle`:
```sh
-compile 'com.bladejava:blade-mvc:2.0.15.ALPHA'
+compile 'com.bladejava:blade-mvc:2.0.15.BETA'
```
ηΌε `main` ε½ζ°εδΈδΈͺ `Hello World`οΌ
diff --git a/pom.xml b/pom.xml
index 989976ccb..9ba7ad0d9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
com.bladejava
blade-mvc
- 2.0.15.ALPHA
+ 2.0.15.BETA
jar
blade
diff --git a/src/main/java/com/blade/Blade.java b/src/main/java/com/blade/Blade.java
index 11f6ad4e9..1dea071a4 100644
--- a/src/main/java/com/blade/Blade.java
+++ b/src/main/java/com/blade/Blade.java
@@ -24,6 +24,7 @@
import com.blade.kit.BladeKit;
import com.blade.kit.JsonKit;
import com.blade.kit.StringKit;
+import com.blade.kit.UncheckedFnKit;
import com.blade.kit.reload.FileChangeDetector;
import com.blade.loader.BladeLoader;
import com.blade.mvc.handler.*;
@@ -832,8 +833,14 @@ public Blade watchEnvChange(boolean watchEnvChange) {
*
* @return return blade instance
*/
- public Blade start() {
- return this.start(null, null);
+ public Blade start(String... args) {
+ Class caller = Arrays.stream(Thread.currentThread().getStackTrace())
+ .filter(st -> "main".equals(st.getMethodName()))
+ .findFirst()
+ .map(StackTraceElement::getClassName)
+ .map(UncheckedFnKit.function(Class::forName))
+ .orElse(null);
+ return this.start(caller, args);
}
/**
diff --git a/src/main/java/com/blade/ioc/annotation/Bean.java b/src/main/java/com/blade/ioc/annotation/Bean.java
index 6342e5602..4bbd238db 100644
--- a/src/main/java/com/blade/ioc/annotation/Bean.java
+++ b/src/main/java/com/blade/ioc/annotation/Bean.java
@@ -8,7 +8,7 @@
* @author biezhi
* @since 1.5
*/
-@Target(ElementType.TYPE)
+@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
diff --git a/src/main/java/com/blade/ioc/annotation/Configuration.java b/src/main/java/com/blade/ioc/annotation/Configuration.java
new file mode 100644
index 000000000..e884ff055
--- /dev/null
+++ b/src/main/java/com/blade/ioc/annotation/Configuration.java
@@ -0,0 +1,15 @@
+package com.blade.ioc.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * @author zhangx
+ * @since 2.0.15
+ **/
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Configuration {
+
+ String name() default "";
+}
diff --git a/src/main/java/com/blade/kit/ReflectKit.java b/src/main/java/com/blade/kit/ReflectKit.java
index 4ca731ec3..32c80f6c7 100644
--- a/src/main/java/com/blade/kit/ReflectKit.java
+++ b/src/main/java/com/blade/kit/ReflectKit.java
@@ -147,6 +147,8 @@ public static Object convert(Type type, String value) {
return DateKit.toLocalDate(value, "yyyy-MM-dd");
} else if (type.equals(LocalDateTime.class)) {
return DateKit.toLocalDateTime(value, "yyyy-MM-dd HH:mm:ss");
+ } else if (type instanceof Class && ((Class) type).isEnum()){
+ return Enum.valueOf((Class)type,value);
}
return value;
}
diff --git a/src/main/java/com/blade/kit/UncheckedFnKit.java b/src/main/java/com/blade/kit/UncheckedFnKit.java
new file mode 100644
index 000000000..4cf1dd079
--- /dev/null
+++ b/src/main/java/com/blade/kit/UncheckedFnKit.java
@@ -0,0 +1,90 @@
+package com.blade.kit;
+
+import com.blade.exception.BladeException;
+
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+/**
+ * @author darren
+ * @date 2019/3/18 11:47
+ */
+public class UncheckedFnKit {
+
+ @FunctionalInterface
+ public interface Consumer_WithExceptions {
+ void accept(T t) throws E;
+ }
+
+ @FunctionalInterface
+ public interface BiConsumer_WithExceptions {
+ void accept(T t, U u) throws E;
+ }
+
+ @FunctionalInterface
+ public interface Function_WithExceptions {
+ R apply(T t) throws E;
+ }
+
+ @FunctionalInterface
+ public interface Supplier_WithExceptions {
+ T get() throws E;
+ }
+
+ @FunctionalInterface
+ public interface Runnable_WithExceptions {
+ void run() throws E;
+ }
+
+ public static Consumer consumer(Consumer_WithExceptions consumer) {
+ return t -> {
+ try {
+ consumer.accept(t);
+ } catch (Throwable throwable) {
+ throw new BladeException(throwable);
+ }
+ };
+ }
+
+ public static BiConsumer biConsumer(BiConsumer_WithExceptions biConsumer) {
+ return (t, u) -> {
+ try {
+ biConsumer.accept(t, u);
+ } catch (Throwable throwable) {
+ throw new BladeException(throwable);
+ }
+ };
+ }
+
+ public static Function function(Function_WithExceptions function) {
+ return t -> {
+ try {
+ return function.apply(t);
+ } catch (Throwable throwable) {
+ throw new BladeException(throwable);
+ }
+ };
+ }
+
+ public static Supplier supplier(Supplier_WithExceptions function) {
+ return () -> {
+ try {
+ return function.get();
+ } catch (Throwable throwable) {
+ throw new BladeException(throwable);
+ }
+ };
+ }
+
+ public static Runnable runnable(Runnable_WithExceptions t) {
+ return ()-> {
+ try {
+ t.run();
+ } catch (Throwable throwable) {
+ throw new BladeException(throwable);
+ }
+ };
+ }
+}
diff --git a/src/main/java/com/blade/kit/json/BeanSerializer.java b/src/main/java/com/blade/kit/json/BeanSerializer.java
index 4ada657e7..af0419664 100755
--- a/src/main/java/com/blade/kit/json/BeanSerializer.java
+++ b/src/main/java/com/blade/kit/json/BeanSerializer.java
@@ -25,6 +25,10 @@ public static Object serialize(SerializeMapping serializeMapping, Object bean) t
return bean.toString().replaceAll("\"", "\\\\\"");
}
+ if (bean instanceof Enum){
+ return bean.toString();
+ }
+
if (ReflectKit.isBasicType(bean.getClass()) || bean instanceof Number || bean instanceof Date
|| bean instanceof LocalDate || bean instanceof LocalDateTime) {
return bean;
@@ -42,8 +46,9 @@ public static Object serialize(SerializeMapping serializeMapping, Object bean) t
}
if (bean instanceof Map) {
- Map map = (Map) bean;
- map.forEach((Object key, Object value) -> {
+ Map beanMap = (Map) bean;
+ Map map = new HashMap(beanMap.size());
+ beanMap.forEach((Object key, Object value) -> {
try {
map.put(key, serialize(serializeMapping, value));
} catch (Exception e) {
@@ -337,6 +342,8 @@ public static T deserialize(Class klass, Object object) {
}
if (ReflectKit.isBasicType(object)) {
return (T) ReflectKit.convert(klass, object.toString());
+ } else if (klass.isEnum()){
+ return (T) Enum.valueOf((Class extends Enum>) klass,object.toString());
} else if (object instanceof Map) {
if (Map.class.isAssignableFrom(klass)) {
return klass.cast(object);
diff --git a/src/main/java/com/blade/mvc/Const.java b/src/main/java/com/blade/mvc/Const.java
index df2c118dd..a18ce3f21 100644
--- a/src/main/java/com/blade/mvc/Const.java
+++ b/src/main/java/com/blade/mvc/Const.java
@@ -31,7 +31,7 @@ public interface Const {
int DEFAULT_SERVER_PORT = 9000;
String DEFAULT_SERVER_ADDRESS = "0.0.0.0";
String LOCAL_IP_ADDRESS = "127.0.0.1";
- String VERSION = "2.0.15.ALPHA";
+ String VERSION = "2.0.15.BETA";
String WEB_JARS = "/webjars/";
String CLASSPATH = BladeKit.getCurrentClassPath();
String CONTENT_TYPE_HTML = "text/html; charset=UTF-8";
diff --git a/src/main/java/com/blade/mvc/RouteContext.java b/src/main/java/com/blade/mvc/RouteContext.java
index f4195a682..c2b99f8e8 100644
--- a/src/main/java/com/blade/mvc/RouteContext.java
+++ b/src/main/java/com/blade/mvc/RouteContext.java
@@ -577,24 +577,6 @@ public boolean isAbort() {
public void initRoute(Route route) {
this.request.initPathParams(route);
this.route = route;
-// if (null != route.getTarget() && route.getTargetType().equals(RouteHandler.class)) {
-// return;
-// }
-// boolean singleton = IocKit.isSingleton(route.getTargetType());
-//
-// if (singleton) {
-// BeanDefine beanDefine = WebContext.blade().ioc().getBeanDefine(route.getTargetType());
-// if (beanDefine.isFieldHasPrototype()) {
-// // reset initialize
-// IocKit.injection(WebContext.blade().ioc(), beanDefine);
-// } else {
-// Object target = WebContext.blade().ioc().getBean(route.getTargetType());
-// this.route.setTarget(target);
-// }
-// } else {
-// Object target = WebContext.blade().ioc().createBean(route.getTargetType());
-// this.route.setTarget(target);
-// }
}
public void injectParameters() {
diff --git a/src/main/java/com/blade/mvc/handler/RouteActionArguments.java b/src/main/java/com/blade/mvc/handler/RouteActionArguments.java
index 60e7ff9e4..10013cf7d 100644
--- a/src/main/java/com/blade/mvc/handler/RouteActionArguments.java
+++ b/src/main/java/com/blade/mvc/handler/RouteActionArguments.java
@@ -166,7 +166,7 @@ private static Object getQueryParam(ParamStruct paramStruct) {
if (ReflectKit.isBasicType(argType) || argType.equals(Date.class)
|| argType.equals(BigDecimal.class) || argType.equals(LocalDate.class)
- || argType.equals(LocalDateTime.class)) {
+ || argType.equals(LocalDateTime.class) || (argType instanceof Class && ((Class) argType).isEnum())) {
String value = request.query(name).orElseGet(() -> getDefaultValue(param.defaultValue(), argType));
diff --git a/src/main/java/com/blade/mvc/route/RouteMatcher.java b/src/main/java/com/blade/mvc/route/RouteMatcher.java
index 7eae42945..1ece1476e 100644
--- a/src/main/java/com/blade/mvc/route/RouteMatcher.java
+++ b/src/main/java/com/blade/mvc/route/RouteMatcher.java
@@ -41,7 +41,7 @@
@Slf4j
public class RouteMatcher {
- private static final Pattern PATH_VARIABLE_PATTERN = Pattern.compile("/(([^:/]*):([^/]+))|(\\.\\*)");
+ private static final Pattern PATH_VARIABLE_PATTERN = Pattern.compile("/(?:([^:/]*):([^/]+))|(\\.\\*)");
private static final String METHOD_NAME = "handle";
// Storage URL and route
diff --git a/src/main/java/com/blade/server/netty/NettyServer.java b/src/main/java/com/blade/server/netty/NettyServer.java
index 662d9e0cd..aea3736bc 100644
--- a/src/main/java/com/blade/server/netty/NettyServer.java
+++ b/src/main/java/com/blade/server/netty/NettyServer.java
@@ -23,6 +23,7 @@
import com.blade.ioc.DynamicContext;
import com.blade.ioc.Ioc;
import com.blade.ioc.annotation.Bean;
+import com.blade.ioc.annotation.Configuration;
import com.blade.ioc.annotation.Value;
import com.blade.ioc.bean.BeanDefine;
import com.blade.ioc.bean.ClassInfo;
@@ -70,6 +71,7 @@
import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
@@ -301,7 +303,18 @@ private void parseAndCreate(Class> clazz) {
Object controller = blade.getBean(clazz);
routeBuilder.addRouter(clazz, controller);
}
-
+ if (null != clazz.getAnnotation(Configuration.class) && clazz.getMethods().length > 0) {
+ Object config = ReflectKit.newInstance(clazz);
+ Arrays.stream(clazz.getMethods())
+ .filter(m -> m.getAnnotation(Bean.class) != null)
+ .forEach(n -> {
+ try {
+ blade.register(n.invoke(config));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ });
+ }
if (ReflectKit.hasInterface(clazz, WebHook.class) && null != clazz.getAnnotation(Bean.class)) {
URLPattern URLPattern = clazz.getAnnotation(URLPattern.class);
if (null == URLPattern) {
diff --git a/src/main/java/com/blade/task/TaskManager.java b/src/main/java/com/blade/task/TaskManager.java
index 14a28719f..08d2e9157 100644
--- a/src/main/java/com/blade/task/TaskManager.java
+++ b/src/main/java/com/blade/task/TaskManager.java
@@ -19,12 +19,10 @@
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import lombok.var;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
import static com.blade.kit.BladeKit.getStartedSymbol;
@@ -41,6 +39,9 @@
public final class TaskManager {
private final static Map TASK_MAP = new HashMap<>(8);
+ private final static ReentrantReadWriteLock rrw = new ReentrantReadWriteLock();
+ private final static Lock readLock = rrw.readLock();
+ private final static Lock writeLock = rrw.writeLock();
private static CronExecutorService cronExecutorService;
@@ -57,21 +58,45 @@ public static CronExecutorService getExecutorService() {
}
public static void addTask(Task task) {
- TASK_MAP.put(task.getName(), task);
+ writeLock.lock();
+ try {
+ TASK_MAP.put(task.getName(), task);
+ } finally {
+ writeLock.unlock();
+ }
log.info("{}Add task [{}]", getStartedSymbol(), task.getName());
}
public static List getTasks() {
- return new ArrayList<>(TASK_MAP.values());
+ Collection values;
+ readLock.lock();
+ try {
+ values = Optional.ofNullable(TASK_MAP.values()).orElse(Collections.EMPTY_LIST);
+ } finally {
+ readLock.unlock();
+ }
+ return new ArrayList<>(values);
}
public static Task getTask(String name) {
- return TASK_MAP.get(name);
+ readLock.lock();
+ try {
+ return TASK_MAP.get(name);
+ } finally {
+ readLock.unlock();
+ }
+
}
public static boolean stopTask(String name) {
- var task = TASK_MAP.get(name);
- return task.stop();
+ Task task;
+ readLock.lock();
+ try {
+ task = TASK_MAP.get(name);
+ } finally {
+ readLock.unlock();
+ }
+ return task == null ? Boolean.FALSE : task.stop();
}
}
diff --git a/src/test/java/com/blade/task/TaskManagerTest.java b/src/test/java/com/blade/task/TaskManagerTest.java
new file mode 100644
index 000000000..5fea19d00
--- /dev/null
+++ b/src/test/java/com/blade/task/TaskManagerTest.java
@@ -0,0 +1,30 @@
+package com.blade.task;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.stream.IntStream;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author PSH
+ * @date 2019/03/16
+ */
+public class TaskManagerTest {
+
+ @Test
+ public void testAddTaskMultiThreading() throws Exception {
+
+ final int tackCount = 500;
+ CountDownLatch downLatch = new CountDownLatch(tackCount);
+ IntStream.range(0, tackCount).forEach(i -> {
+ Task task = new Task("task-" + i, null, Integer.MAX_VALUE);
+ new Thread(() -> {
+ TaskManager.addTask(task);
+ downLatch.countDown();
+ }).start();
+ });
+
+ downLatch.await();
+ Assert.assertEquals(tackCount, TaskManager.getTasks().size());
+ }
+}