org.lastaflute.web.ruts.config.analyzer.ExecuteArgAnalyzer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of lastaflute Show documentation
Show all versions of lastaflute Show documentation
Typesafe Web Framework for LeAn STArtup with DBFlute and Java8
/*
* Copyright 2014-2015 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
*
* 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 org.lastaflute.web.ruts.config.analyzer;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.dbflute.helper.message.ExceptionMessageBuilder;
import org.dbflute.util.DfReflectionUtil;
import org.lastaflute.web.exception.ActionFormNotLastParameterException;
import org.lastaflute.web.exception.ExecuteMethodOptionalParameterGenericNotFoundException;
import org.lastaflute.web.exception.ExecuteMethodOptionalParameterGenericNotScalarException;
import org.lastaflute.web.util.LaActionExecuteUtil;
/**
* @author jflute
*/
public class ExecuteArgAnalyzer {
// ===================================================================================
// Definition
// ==========
public static final String FORM_SUFFIX = "Form";
// ===================================================================================
// Analyze
// =======
public void analyzeExecuteArg(Method executeMethod, ExecuteArgBox box) {
List> urlParamTypeList = null; // lazy loaded
Parameter formParam = null;
final Parameter[] parameters = executeMethod.getParameters();
if (parameters.length > 0) {
boolean formEnd = false;
for (Parameter parameter : parameters) {
if (formEnd) {
throwActionFormNotLastParameterException(executeMethod);
}
checkNonGenericParameter(executeMethod, parameter);
if (isActionFormParameter(parameter)) {
formParam = parameter;
formEnd = true;
} else {
if (urlParamTypeList == null) {
urlParamTypeList = new ArrayList>(4);
}
urlParamTypeList.add(parameter.getType());
}
}
}
box.setUrlParamTypeList(prepareUrlParamTypeList(urlParamTypeList));
box.setOptionalGenericTypeMap(prepareOptionalGenericTypeMap(executeMethod));
box.setFormType(prepareFormType(formParam));
box.setListFormParameter(prepareListFormParameter(formParam));
}
// ===================================================================================
// Form Parameter
// ==============
public boolean isActionFormParameter(Parameter parameter) {
return isBeanActionFormParameter(parameter) || isListActionFormParameter(parameter);
}
// -----------------------------------------------------
// Bean Form
// ---------
protected boolean isBeanActionFormParameter(Parameter parameter) {
return isBeanActionFormType(parameter.getType());
}
protected boolean isBeanActionFormType(Type parameterType) {
final String typeName = parameterType.getTypeName();
return !typeName.startsWith("java.") && typeName.endsWith(getFormSuffix());
}
protected String getFormSuffix() {
return FORM_SUFFIX;
}
// -----------------------------------------------------
// List Form
// ---------
protected boolean isListActionFormParameter(Parameter parameter) {
return findListFormGenericType(parameter) != null;
}
protected Class> findListFormGenericType(Parameter parameter) {
if (List.class.equals(parameter.getType())) { // just List
final Type pt = parameter.getParameterizedType();
final Class> genericType = DfReflectionUtil.getGenericFirstClass(pt); // almost not null, already checked
return genericType != null && isBeanActionFormType(genericType) ? genericType : null; // e.g. List
}
return null;
}
// -----------------------------------------------------
// Check Form
// ----------
protected void throwActionFormNotLastParameterException(Method executeMethod) {
final ExceptionMessageBuilder br = new ExceptionMessageBuilder();
br.addNotice("Not allowed to define argument after ActionForm.");
br.addItem("Advice");
br.addElement("ActionForm should be defined at last parameter");
br.addElement("at @Execute method.");
br.addElement(" (x):");
br.addElement(" public HtmlResponse index(SeaForm form, int pageNumber) { // *NG");
br.addElement(" (o):");
br.addElement(" public HtmlResponse index(int pageNumber, SeaForm form) { // OK");
br.addItem("Execute Method");
br.addElement(LaActionExecuteUtil.buildSimpleMethodExp(executeMethod));
final String msg = br.buildExceptionMessage();
throw new ActionFormNotLastParameterException(msg);
}
// -----------------------------------------------------
// Prepare Form
// ------------
protected Class> prepareFormType(Parameter formParam) {
return formParam != null ? formParam.getType() : null;
}
protected Parameter prepareListFormParameter(Parameter formParam) { // already checked but just in case
return (formParam != null && formParam.getParameterizedType() instanceof ParameterizedType) ? formParam : null;
}
// ===================================================================================
// Optional Generic Type
// =====================
protected Map> prepareOptionalGenericTypeMap(Method executeMethod) {
final Parameter[] parameters = executeMethod.getParameters();
if (parameters.length == 0) {
return Collections.emptyMap();
}
final Map> optionalGenericTypeMap = new LinkedHashMap>(4);
int index = 0;
for (Parameter parameter : parameters) {
if (isOptionalParameterType(parameter.getType())) {
final Type parameterizedType = parameter.getParameterizedType();
final Class> genericType = DfReflectionUtil.getGenericFirstClass(parameterizedType);
checkExecuteMethodOptionalParameter(executeMethod, parameterizedType, genericType);
optionalGenericTypeMap.put(index, genericType);
}
++index;
}
return Collections.unmodifiableMap(optionalGenericTypeMap);
}
protected void checkExecuteMethodOptionalParameter(Method executeMethod, final Type parameterizedType, final Class> genericType) {
if (genericType == null) { // e.g. non-generic optional
throwExecuteMethodOptionalParameterGenericNotFoundException(executeMethod, parameterizedType);
}
if (genericType.equals(Object.class)) { // e.g. wild-card generic or just Object
throwExecuteMethodOptionalParameterGenericNotScalarException(executeMethod, parameterizedType, genericType);
}
}
protected boolean isOptionalParameterType(Class> paramType) {
return LaActionExecuteUtil.isOptionalParameterType(paramType);
}
protected void throwExecuteMethodOptionalParameterGenericNotFoundException(Method executeMethod, Type parameterizedType) {
final ExceptionMessageBuilder br = new ExceptionMessageBuilder();
br.addNotice("Not found the generic type for the optional parameter.");
br.addItem("Execute Method");
br.addElement(LaActionExecuteUtil.buildSimpleMethodExp(executeMethod));
br.addItem("Parameterized Type");
br.addElement(parameterizedType);
final String msg = br.buildExceptionMessage();
throw new ExecuteMethodOptionalParameterGenericNotFoundException(msg);
}
protected void throwExecuteMethodOptionalParameterGenericNotScalarException(Method executeMethod, Type parameterizedType,
Class> genericType) {
final ExceptionMessageBuilder br = new ExceptionMessageBuilder();
br.addNotice("Not scalar generic type for the optional parameter.");
br.addItem("Advice");
br.addElement("Optional generic type should be scalar type e.g. Integer, String");
br.addElement(" (x):");
br.addElement(" public HtmlResponse index(OptionalThing> opt) { // *NG");
br.addElement(" (x):");
br.addElement(" public HtmlResponse index(OptionalThing