Skip to content

Commit

Permalink
support SimpleExpression, e.g. new org.docksidestage.Sea() #39
Browse files Browse the repository at this point in the history
  • Loading branch information
jflute committed Sep 26, 2024
1 parent f5ceea0 commit 6389ed3
Show file tree
Hide file tree
Showing 2 changed files with 248 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,19 @@
import org.lastaflute.di.util.LdiSrl;
import org.lastaflute.di.util.LdiStringUtil;
import org.lastaflute.di.util.tiger.LdiReflectionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* @author jflute
*/
public class SimpleExpressionPlainHook implements ExpressionPlainHook {

// ===================================================================================
// Definition
// ==========
private static final Logger logger = LoggerFactory.getLogger(SimpleExpressionPlainHook.class);

protected static final ExpressionCastResolver castResolver = new ExpressionCastResolver();

// ===================================================================================
Expand Down Expand Up @@ -79,6 +86,10 @@ protected Object actuallyHookPlainly(String exp, LaContainer container, Class<?>
if (isReallyResolved(resovled)) {
return resovled;
}
resovled = resolveSimpleNewExp(exp, container, resultType); // e.g. new org.docksidestage.Sea()
if (isReallyResolved(resovled)) {
return resovled;
}
resovled = resolveSimpleTypeExp(exp, container, resultType); // e.g. @org.docksidestage.Sea@class
if (isReallyResolved(resovled)) {
return resovled;
Expand Down Expand Up @@ -149,6 +160,32 @@ protected Object resolveSimpleEqualEqual(String exp, LaContainer container, Clas
return null;
}

// ===================================================================================
// Simple New
// ==========
protected Object resolveSimpleNewExp(String exp, LaContainer container, Class<?> resultType) { // @since 1.0.0
if (exp.startsWith("new ") && exp.endsWith("()") && exp.contains(".")) {
final String rear = LdiSrl.substringFirstRear(exp, "new "); // e.g. org.docksidestage.Sea()
final String fqcn = LdiSrl.substringLastFront(rear, "()"); // e.g. org.docksidestage.Sea
final Class<Object> clazz;
try {
clazz = LdiReflectionUtil.forName(fqcn);
} catch (RuntimeException continued) { // may be framework bug
logger.debug("Failed to find class for the name: exp=" + exp + ", fqcn=" + fqcn, continued);
return null;
}
final Object instance;
try {
instance = LdiReflectionUtil.newInstance(clazz);
} catch (RuntimeException continued) { // may be framework bug
logger.debug("Failed to new instance (of expression): exp=" + exp + ", class=" + clazz, continued);
return null;
}
return instance;
}
return null;
}

// ===================================================================================
// Simple Type Expression
// ======================
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,141 @@
*/
package org.lastaflute.di.core.expression.dwarf;

import java.util.HashMap;
import java.util.Map;

import org.lastaflute.di.core.LaContainer;
import org.lastaflute.di.core.meta.impl.LaContainerImpl;
import org.lastaflute.di.unit.UnitLastaDiTestCase;
import org.lastaflute.jta.core.LaTransaction;

/**
* @author jflute
*/
public class SimpleExpressionPlainHookTest extends UnitLastaDiTestCase {

// ===================================================================================
// new Constructor
// ===============
public void test_hookPlainly_newConstructor_basic() {
// ## Arrange ##
SimpleExpressionPlainHook hook = new SimpleExpressionPlainHook();
String exp = "new org.lastaflute.jta.core.LaTransaction()";
Map<String, Object> contextMap = new HashMap<>();
LaContainer container = createProviderContainer(new MyMockProvider(false));
Class<?> resultType = LaTransaction.class; // however unused

// ## Act ##
Object result = hook.hookPlainly(exp, contextMap, container, resultType);

// ## Assert ##
assertNotNull(result);
assertTrue(result instanceof LaTransaction);
}

// ===================================================================================
// Method Chain
// ============
// -----------------------------------------------------
// Config get()
// ------------
public void test_hookPlainly_methodChain_config_get() {
// ## Arrange ##
SimpleExpressionPlainHook hook = new SimpleExpressionPlainHook();
String exp = "provider.config().getJdbcUrl()";
Map<String, Object> contextMap = new HashMap<>();
LaContainer container = createProviderContainer(new MyMockProvider(false));
Class<?> resultType = String.class;

// ## Act ##
Object result = hook.hookPlainly(exp, contextMap, container, resultType);

// ## Assert ##
assertNotNull(result);
assertTrue(result instanceof String);
assertEquals(MyMockConfig.JDBC_URL, (String) result);
}

// -----------------------------------------------------
// Config getOrDefault()
// ---------------------
public void test_hookPlainly_methodChain_config_getOrDefault_null() {
// ## Arrange ##
SimpleExpressionPlainHook hook = new SimpleExpressionPlainHook();
String exp = "provider.config().getOrDefault(\"jdbc.url\", null)";
Map<String, Object> contextMap = new HashMap<>();
LaContainer container = createProviderContainer(new MyMockProvider(false));
Class<?> resultType = String.class;

// ## Act ##
Object result = hook.hookPlainly(exp, contextMap, container, resultType);

// ## Assert ##
assertNotNull(result);
assertEquals(ExpressionPlainHook.NULL_RETURN, result);
}
// #for_now jflute unsupported if valid default value and no space before comma for now (2024/09/23)

// -----------------------------------------------------
// Config Determination
// --------------------
public void test_hookPlainly_methodChain_configDetermination() { // since 1.0.0
// ## Arrange ##
SimpleExpressionPlainHook hook = new SimpleExpressionPlainHook();
String exp = "provider.config().isDevelopmentHere()";
Map<String, Object> contextMap = new HashMap<>();
LaContainer container = createProviderContainer(new MyMockProvider(true));
Class<?> resultType = Boolean.class;

// ## Act ##
Object result = hook.hookPlainly(exp, contextMap, container, resultType);

// ## Assert ##
assertNotNull(result);
assertTrue(result instanceof Boolean);
assertTrue((Boolean) result);
}

// ===================================================================================
// Hatena Colon
// ============
public void test_hookPlainly_hatenaColon_integer_false() { // since 1.0.0
// ## Arrange ##
SimpleExpressionPlainHook hook = new SimpleExpressionPlainHook();
String exp = "provider.config().isDevelopmentHere() ? new java.lang.Integer(1) : new java.lang.Integer(2)";
Map<String, Object> contextMap = new HashMap<>();
LaContainer container = createProviderContainer(new MyMockProvider(false));
Class<?> resultType = Integer.class;

// ## Act ##
Object result = hook.hookPlainly(exp, contextMap, container, resultType);

// ## Assert ##
assertNotNull(result);
assertTrue(result instanceof Integer);
assertEquals(2, (int) result);
}

public void test_hookPlainly_hatenaColon_integer_true() { // since 1.0.0
// ## Arrange ##
SimpleExpressionPlainHook hook = new SimpleExpressionPlainHook();
String exp = "provider.config().isDevelopmentHere() ? new java.lang.Integer(1) : new java.lang.Integer(2)";
Map<String, ? extends Object> contextMap = new HashMap<>();
LaContainer container = createProviderContainer(new MyMockProvider(true));
Class<?> resultType = Integer.class;

// ## Act ##
Object result = hook.hookPlainly(exp, contextMap, container, resultType);

// ## Assert ##
assertNotNull(result);
assertTrue(result instanceof Integer);
assertEquals(1, (int) result);
}

// ===================================================================================
// Detail Method
// =============
public void test_resolveSimpleNumber_basic() {
// ## Arrange ##
SimpleExpressionPlainHook hook = new SimpleExpressionPlainHook();
Expand All @@ -40,7 +166,92 @@ public void test_resolveSimpleNumber_basic() {
assertEquals(99999999999L, hook.resolveSimpleNumber("99999999999", createContainer(), Object.class));
}

// ===================================================================================
// Test Helper
// ===========
private LaContainer createContainer() {
return new LaContainerImpl();
}

private LaContainer createContainer(Map<Object, Object> componentMap) {
return new LaContainerImpl() {
@Override
public boolean hasComponentDef(Object componentKey) {
Object mock = componentMap.get(componentKey);
if (mock != null) {
return true;
}
return super.hasComponentDef(componentKey);
}

@SuppressWarnings("unchecked")
@Override
public <COMPONENT> COMPONENT getComponent(Object componentKey) {
Object mock = componentMap.get(componentKey);
if (mock != null) {
return (COMPONENT) mock;
}
return super.getComponent(componentKey);
}
};
}

private LaContainer createProviderContainer(MyMockProvider provider) {
Map<Object, Object> componentMap = new HashMap<>();
componentMap.put("provider", provider);
return createContainer(componentMap);
}

public static class MyMockProvider {

private boolean developmentHere;

public MyMockProvider(boolean developmentHere) {
this.developmentHere = developmentHere;
}

public MyMockConfig config() {
return new MyMockConfig(developmentHere);
}
}

public static class MyMockConfig {

public static final String JDBC_URL = "jdbc:mysql://localhost:3306/resortlinedb";

private boolean developmentHere;

public MyMockConfig(boolean developmentHere) {
this.developmentHere = developmentHere;
}

public boolean isDevelopmentHere() {
return developmentHere;
}

public String getJdbcUrl() {
return JDBC_URL;
}

public String getOrDefault(String key, Object defaultValue) {
if ("jdbc.url".equals(key)) {
return (String) defaultValue; // always default
}
return null;
}
}

public static class Sea {

private final Integer number;

public Sea(Integer number) {
super();
this.number = number;
}

public Integer getNumber() {
return number;
}
}
}

0 comments on commit 6389ed3

Please sign in to comment.