Skip to content

Commit 676fdee

Browse files
authored
Merge pull request #12 from ELDEpendenci/develop
組件現在可以接受 null 數值
2 parents fba9697 + 20d0206 commit 676fdee

File tree

12 files changed

+90
-64
lines changed

12 files changed

+90
-64
lines changed

.github/workflows/publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
env:
2-
version: 0.1.3 # 你的版本名稱
2+
version: 0.1.3.1 # 你的版本名稱
33
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
44
plugin_name: ELDependenci-MVC-plugin
55

ELDependenci-MVC-plugin/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<modelVersion>4.0.0</modelVersion>
1111

1212
<artifactId>ELDependenci-MVC-plugin</artifactId>
13-
<version>${project.parent.version}</version>
13+
<version>${project.parent.version}.1</version>
1414

1515
<dependencies>
1616
<dependency>

ELDependenci-MVC-plugin/src/main/java/com/ericlam/mc/eldgui/ELDGUI.java

Lines changed: 38 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import com.ericlam.mc.eldgui.view.BukkitRedirectView;
1616
import com.ericlam.mc.eldgui.view.BukkitView;
1717
import com.ericlam.mc.eldgui.view.LoadingView;
18-
import com.ericlam.mc.eldgui.view.View;
1918
import com.google.inject.Injector;
2019
import com.google.inject.TypeLiteral;
2120
import org.bukkit.Bukkit;
@@ -28,17 +27,15 @@
2827
import java.lang.annotation.Annotation;
2928
import java.lang.reflect.Method;
3029
import java.lang.reflect.ParameterizedType;
31-
import java.util.Arrays;
32-
import java.util.List;
33-
import java.util.Map;
34-
import java.util.Optional;
30+
import java.util.*;
3531
import java.util.concurrent.ConcurrentHashMap;
3632
import java.util.function.Consumer;
3733
import java.util.function.Function;
3834
import java.util.stream.Collectors;
3935

4036
public final class ELDGUI {
4137

38+
private static final Map<Class<?>, Method[]> declaredMethodMap = new ConcurrentHashMap<>();
4239
private static final Logger LOGGER = LoggerFactory.getLogger(ELDGUI.class);
4340

4441

@@ -49,7 +46,6 @@ public final class ELDGUI {
4946
private final LifeCycleManager lifeCycleManager;
5047

5148
private final Class<?> controllerCls;
52-
private final Object controller;
5349
private final Injector injector;
5450
private final UISession session;
5551
private final Player owner;
@@ -61,6 +57,7 @@ public final class ELDGUI {
6157
private final Consumer<Player> onDestroy;
6258
private final ViewJumper goTo;
6359
private final BukkitView<? extends LoadingView, Void> loadingView;
60+
private final Method[] declaredMethods;
6461

6562

6663
private ELDGView<?> currentView;
@@ -79,7 +76,6 @@ public ELDGUI(
7976
) {
8077

8178
this.session = session;
82-
this.controller = controller;
8379
this.injector = injector;
8480
this.owner = owner;
8581
this.onDestroy = onDestroy;
@@ -91,16 +87,22 @@ public ELDGUI(
9187
methodParseManager = managerFactory.buildParseManager(this::initMethodParseManager);
9288
returnTypeManager = managerFactory.buildReturnTypeManager(this::initReturnTypeManager);
9389
this.lifeCycleManager = new LifeCycleManager(controller, methodParseManager);
90+
this.controllerCls = controller.getClass();
91+
92+
if (declaredMethodMap.containsKey(controllerCls)) {
93+
this.declaredMethods = declaredMethodMap.get(controllerCls);
94+
} else {
95+
this.declaredMethods = controllerCls.getDeclaredMethods();
96+
declaredMethodMap.put(controllerCls, declaredMethods);
97+
}
9498

9599
var customQualifier = eldgmvcInstallation.getQualifierMap();
96-
this.eventHandlerMap.put(InventoryClickEvent.class, new ELDGClickEventHandler(controller, methodParseManager, returnTypeManager, customQualifier));
97-
this.eventHandlerMap.put(InventoryDragEvent.class, new ELDGDragEventHandler(controller, methodParseManager, returnTypeManager, customQualifier));
100+
this.eventHandlerMap.put(InventoryClickEvent.class, new ELDGClickEventHandler(controller, methodParseManager, returnTypeManager, customQualifier, declaredMethods));
101+
this.eventHandlerMap.put(InventoryDragEvent.class, new ELDGDragEventHandler(controller, methodParseManager, returnTypeManager, customQualifier, declaredMethods));
98102
this.itemGetterMap.put(InventoryClickEvent.class.getSimpleName(), e -> ((InventoryClickEvent) e).getCurrentItem());
99103
this.itemGetterMap.put(InventoryDragEvent.class.getSimpleName(), e -> ((InventoryDragEvent) e).getOldCursor());
100104

101105

102-
this.controllerCls = controller.getClass();
103-
104106
this.lifeCycleManager.onLifeCycle(PostConstruct.class);
105107

106108
Optional<Class<? extends LoadingView>> loadingViewOpt = Optional.ofNullable(this.controllerCls.getAnnotation(AsyncLoadingView.class)).map(AsyncLoadingView::value);
@@ -140,7 +142,7 @@ private synchronized void jumpToController(BukkitRedirectView redirectView) {
140142
public void initIndexView(Object controller) {
141143
LOGGER.debug("initializing index view"); // debug
142144
try {
143-
Optional<Method> indexMethod = Arrays.stream(controllerCls.getDeclaredMethods()).filter(m -> m.getName().equalsIgnoreCase("index")).findAny();
145+
Optional<Method> indexMethod = Arrays.stream(declaredMethods).filter(m -> m.getName().equalsIgnoreCase("index")).findAny();
144146
if (indexMethod.isEmpty())
145147
throw new IllegalStateException("cannot find index method from " + controllerCls);
146148
Method index = indexMethod.get();
@@ -203,7 +205,7 @@ private void initMethodParseManager(MethodParseManager parser) {
203205
FromPattern pattern = (FromPattern) Arrays.stream(annotations).filter(a -> a.annotationType() == FromPattern.class).findAny().orElseThrow(() -> new IllegalStateException("cannot find @FromPattern in List<ItemStack> parameters"));
204206
if (t instanceof ParameterizedType) {
205207
var parat = (ParameterizedType) t;
206-
if (parat.getActualTypeArguments()[0] == ItemStack.class && parat.getRawType() == List.class){
208+
if (parat.getActualTypeArguments()[0] == ItemStack.class && parat.getRawType() == List.class) {
207209
return this.currentView.getEldgContext().getItems(pattern.value());
208210
}
209211
}
@@ -221,48 +223,42 @@ private void initMethodParseManager(MethodParseManager parser) {
221223
parser.registerParser((t, annos) -> Arrays.stream(annos).anyMatch(a -> a.annotationType() == ModelAttribute.class),
222224
(annotations, type, event) -> {
223225
ModelAttribute modelAttribute = (ModelAttribute) Arrays.stream(annotations).filter(a -> a.annotationType() == ModelAttribute.class).findAny().orElseThrow(() -> new IllegalStateException("cannot find @ModelAttribute"));
224-
var context = this.currentView.getEldgContext();
225226
if (type instanceof ParameterizedType)
226227
throw new IllegalStateException("model attribute cannot be generic type");
227228
var model = ((Class<?>) type);
228-
229-
Map<String, Object> fieldMap = context.getItems(modelAttribute.value())
230-
.stream()
231-
.filter(item -> context.getAttribute(item, AttributeController.FIELD_TAG) != null)
232-
.collect(Collectors
233-
.toMap(
234-
item -> context.getAttribute(item, AttributeController.FIELD_TAG),
235-
item -> Optional.ofNullable(context.getAttribute(item, AttributeController.VALUE_TAG)).orElseThrow(() -> new IllegalStateException("The value tag of " + item.toString() + " is null."))
236-
)
237-
);
229+
var fieldMap = getFieldMap(modelAttribute.value());
238230
Map<String, Object> toConvert = PersistDataUtils.toNestedMap(fieldMap);
239231
LOGGER.debug("using " + toConvert + " to create instance of " + model);
240232
return PersistDataUtils.mapToObject(toConvert, model);
241233
});
242234
parser.registerParser((t, annos) -> Arrays.stream(annos).anyMatch(a -> a.annotationType() == MapAttribute.class),
243235
(annotations, type, event) -> {
244236
MapAttribute attribute = (MapAttribute) Arrays.stream(annotations).filter(a -> a.annotationType() == MapAttribute.class).findAny().orElseThrow(() -> new IllegalStateException("cannot find MapAttribute annotation"));
245-
var context = this.currentView.getEldgContext();
246237
boolean isMap = false;
247-
if (type instanceof ParameterizedType){
248-
var parat = (ParameterizedType)type;
238+
if (type instanceof ParameterizedType) {
239+
var parat = (ParameterizedType) type;
249240
isMap = parat.getRawType() == Map.class && parat.getActualTypeArguments()[0] == String.class && parat.getActualTypeArguments()[1] == Object.class;
250241
}
251242

252243
if (!isMap) throw new IllegalStateException("@MapAttribute 必須使用 Map<String, Object> 作為其類型");
253-
Map<String, Object> fieldMap = context.getItems(attribute.value())
254-
.stream()
255-
.filter(item -> context.getAttribute(item, AttributeController.FIELD_TAG) != null)
256-
.collect(Collectors
257-
.toMap(
258-
item -> context.getAttribute(item, AttributeController.FIELD_TAG),
259-
item -> Optional.ofNullable(context.getAttribute(item, AttributeController.VALUE_TAG)).orElseThrow(() -> new IllegalStateException("The value tag of " + item.toString() + " is null."))
260-
)
261-
);
244+
Map<String, Object> fieldMap = getFieldMap(attribute.value());
262245
return PersistDataUtils.toNestedMap(fieldMap);
263246
});
264247
}
265248

249+
private Map<String, Object> getFieldMap(char pattern){
250+
if (this.currentView == null) throw new IllegalStateException("currentView is null");
251+
var context = this.currentView.getEldgContext();
252+
Map<String, Object> fieldMap = new HashMap<>();
253+
for (ItemStack item : context.getItems(pattern)) {
254+
String field = context.getAttribute(item, AttributeController.FIELD_TAG);
255+
if (field == null) continue;
256+
Object value = context.getAttribute(item, AttributeController.VALUE_TAG);
257+
fieldMap.put(field, value);
258+
}
259+
return fieldMap;
260+
}
261+
266262
private ItemStack getItemByEvent(InventoryEvent e) {
267263
return Optional.ofNullable(e).map(ee -> itemGetterMap.get(ee.getEventName())).map(f -> f.apply(e)).orElseThrow(() -> new IllegalStateException("no item return by the event or the event is null"));
268264
}
@@ -315,7 +311,12 @@ private void handleException(Exception ex) {
315311
Class<? extends ExceptionViewHandler> exceptionViewHandler = exceptionViewHandlerOpt.orElseGet(eldgmvcInstallation::getDefaultExceptionHandler);
316312
ExceptionViewHandler viewHandlerIns = injector.getInstance(exceptionViewHandler);
317313
UIController fromController = controllerCls.getAnnotation(UIController.class);
318-
Arrays.stream(exceptionViewHandler.getDeclaredMethods())
314+
Method[] declaredMethods = Optional.ofNullable(declaredMethodMap.get(exceptionViewHandler)).orElseGet(() -> {
315+
var methods = exceptionViewHandler.getDeclaredMethods();
316+
declaredMethodMap.put(exceptionViewHandler, methods);
317+
return methods;
318+
});
319+
Arrays.stream(declaredMethods)
319320
.filter(m -> m.isAnnotationPresent(HandleException.class))
320321
.filter(m -> Arrays.stream(m.getAnnotation(HandleException.class).value()).anyMatch(v -> {
321322
Class<?> superCls = ex.getClass();

ELDependenci-MVC-plugin/src/main/java/com/ericlam/mc/eldgui/ELDGView.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -333,15 +333,15 @@ public <C> C getAttributePrimitive(Class<C> type, ItemStack itemStack, String ke
333333

334334
public Map<String, Object> getAsMap(ItemStack item) {
335335
String id = getAttributePrimitive(String.class, item, "id");
336-
return Optional.ofNullable(attributeMap.get(id)).map(ImmutableMap::copyOf).orElseGet(ImmutableMap::of);
336+
return Optional.ofNullable(attributeMap.get(id)).map(HashMap::new).orElseGet(HashMap::new);
337337
}
338338

339339
@Override
340-
public <C> C getAttribute(ItemStack item, String key) {
340+
public synchronized <C> C getAttribute(ItemStack item, String key) {
341341
// instead of using persist data type, use map
342342
//return getObjectAttribute(item, key);
343343
String id = getIdFromItem(item);
344-
attributeMap.putIfAbsent(id, new ConcurrentHashMap<>());
344+
attributeMap.putIfAbsent(id, new HashMap<>());
345345
LOGGER.debug("item (" + item.getType() + ") is now: " + getAsMap(item).toString());
346346
return (C) attributeMap.get(id).get(key);
347347
}
@@ -393,11 +393,11 @@ public <C> void setAttributePrimitive(Class<C> type, ItemStack itemStack, String
393393
}
394394

395395
@Override
396-
public void setAttribute(ItemStack itemStack, String key, Object value) {
396+
public synchronized void setAttribute(ItemStack itemStack, String key, Object value) {
397397
// instead of using persist data type, use map
398398
//this.setObjectAttribute(itemStack, key, value);
399399
String id = getIdFromItem(itemStack);
400-
this.attributeMap.putIfAbsent(id, new ConcurrentHashMap<>());
400+
this.attributeMap.putIfAbsent(id, new HashMap<>());
401401
this.attributeMap.get(id).put(key, value);
402402

403403
LOGGER.debug("item (" + itemStack.getType() + ") is now: " + getAsMap(itemStack).toString());
@@ -410,7 +410,7 @@ public <C> void setAttributePrimitive(Class<C> type, char pattern, String key, O
410410

411411

412412
@Override
413-
public void setAttribute(char pattern, String key, Object value) {
413+
public synchronized void setAttribute(char pattern, String key, Object value) {
414414
getItems(pattern).forEach(item -> setAttribute(item, key, value));
415415
}
416416

ELDependenci-MVC-plugin/src/main/java/com/ericlam/mc/eldgui/PersistDataUtils.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import org.slf4j.Logger;
1313
import org.slf4j.LoggerFactory;
1414

15+
import javax.annotation.Nonnull;
1516
import java.io.IOException;
1617
import java.lang.reflect.Field;
1718
import java.lang.reflect.InvocationTargetException;
@@ -146,6 +147,9 @@ public static <T> T mapToObject(Map<String, Object> map, Class<T> beanClass) {
146147
Map<String, Object> m = (Map<String, Object>) value;
147148
value = mapToObject(m, field.getType());
148149
}
150+
if (value == null && field.isAnnotationPresent(Nonnull.class)){
151+
throw new IllegalStateException("property assigned @Nonnull but setting null value.");
152+
}
149153
try {
150154
field.set(obj, value);
151155
}catch (IllegalAccessException e) {

ELDependenci-MVC-plugin/src/main/java/com/ericlam/mc/eldgui/demo/error/StaticErrorView.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public void renderView(Exception ex, UIContext context) {
2626
.components(
2727
button.icon(Material.BARRIER)
2828
.title("&cError: " + ex.getClass().getSimpleName())
29-
.lore("&c".concat(ex.getMessage()))
29+
.lore("&c" + ex.getMessage())
3030
.create()
3131
);
3232
}

ELDependenci-MVC-plugin/src/main/java/com/ericlam/mc/eldgui/demo/test/TestController.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@ public void beforeCreate(Player player){
2525

2626

2727
@ClickMapping(view = TestView.class, pattern = 'A')
28-
public void onClick(@ModelAttribute('Z') TestModel test, Player player, @MapAttribute('Z') Map<String, Object> map){
28+
public BukkitView<?, ?> onClick(@ModelAttribute('Z') TestModel test, Player player, @MapAttribute('Z') Map<String, Object> map){
2929
player.sendMessage(test.toString());
3030
player.sendMessage(map.toString());
31+
return null;
3132
}
3233

3334

ELDependenci-MVC-plugin/src/main/java/com/ericlam/mc/eldgui/demo/test/TestModel.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,16 @@ public class TestModel {
1313

1414
public LocalTime testTime;
1515

16+
// test null
17+
public String txt;
18+
1619
@Override
1720
public String toString() {
1821
return "TestModel{" +
19-
"testColor=" + testColor.toString() +
20-
", testDate=" + testDate.toString() +
21-
", testTime=" + testTime.toString() +
22+
"testColor=" + testColor +
23+
", testDate=" + testDate +
24+
", testTime=" + testTime +
25+
", txt='" + txt + '\'' +
2226
'}';
2327
}
2428
}

ELDependenci-MVC-plugin/src/main/java/com/ericlam/mc/eldgui/demo/test/TestView.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.ericlam.mc.eldgui.demo.test;
22

3+
import com.ericlam.mc.eldgui.component.AttributeController;
34
import com.ericlam.mc.eldgui.component.factory.ButtonFactory;
45
import com.ericlam.mc.eldgui.component.factory.DateSelectorFactory;
56
import com.ericlam.mc.eldgui.component.factory.RGBSelectorFactory;
@@ -47,6 +48,11 @@ public void renderView(Void model, UIContext context) {
4748
.bindInput("testTime", LocalTime.now())
4849
.label("&aTime Select: (shift move unit, click to +/-, middle to input)")
4950
.icon(Material.CLOCK)
51+
.create(),
52+
button.icon(Material.PAPER)
53+
.title("test null string")
54+
.bind(AttributeController.FIELD_TAG, "txt")
55+
.bind(AttributeController.VALUE_TAG, null)
5056
.create()
5157
)
5258
.and()

ELDependenci-MVC-plugin/src/main/java/com/ericlam/mc/eldgui/event/ELDGClickEventHandler.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@
1515
public final class ELDGClickEventHandler extends ELDGEventHandler<ClickMapping, InventoryClickEvent> {
1616

1717

18-
public ELDGClickEventHandler(Object controller, MethodParseManager parseManager, ReturnTypeManager returnTypeManager, Map<Class<? extends Annotation>, MVCInstallation.QualifierFilter<? extends Annotation>> customQualifier) {
19-
super(controller, parseManager, returnTypeManager, customQualifier);
18+
public ELDGClickEventHandler(Object controller, MethodParseManager parseManager, ReturnTypeManager returnTypeManager, Map<Class<? extends Annotation>, MVCInstallation.QualifierFilter<? extends Annotation>> customQualifier, Method[] declaredMethods) {
19+
super(controller, parseManager, returnTypeManager, customQualifier, declaredMethods);
2020
}
2121

2222
@Override
23-
protected Map<ClickMapping, Method> loadAllHandlers(Object controller) {
24-
return Arrays.stream(controller.getClass().getDeclaredMethods()).parallel()
23+
protected Map<ClickMapping, Method> loadAllHandlers(Method[] declaredMethods) {
24+
return Arrays.stream(declaredMethods).parallel()
2525
.filter(m -> m.isAnnotationPresent(ClickMapping.class))
2626
.collect(Collectors.toMap(m -> m.getAnnotation(ClickMapping.class), m -> m));
2727
}

0 commit comments

Comments
 (0)