diff --git a/org.adempiere.base/src/org/adempiere/base/annotation/Parameter.java b/org.adempiere.base/src/org/adempiere/base/annotation/Parameter.java
new file mode 100644
index 0000000000..d902560553
--- /dev/null
+++ b/org.adempiere.base/src/org/adempiere/base/annotation/Parameter.java
@@ -0,0 +1,51 @@
+/******************************************************************************
+ * Product: iDempiere ERP & CRM Smart Business Solution *
+ * This program is free software; you can redistribute it and/or modify it *
+ * under the terms version 2 of the GNU General Public License as published *
+ * by the Free Software Foundation. This program is distributed in the hope *
+ * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
+ * See the GNU General Public License for more details. *
+ * You should have received a copy of the GNU General Public License along *
+ * with this program; if not, write to the Free Software Foundation, Inc., *
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
+ *****************************************************************************/
+package org.adempiere.base.annotation;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import static java.lang.annotation.ElementType.FIELD;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import org.compiere.model.X_AD_Process_Para;
+import org.compiere.process.SvrProcess;
+
+/**
+ * Tags a process class field as a process parameter in order to have its value set automatically.
+ * Class fields are matched against process parameters using the following heuristics:
+ * [1] If the parameter annotation has a name, then it must match exactly the process parameter
+ * metadata definition. For example:
+ * @Parameter(name="C_BPartner_ID") int foo will fill foo with
+ * the value of the parameter named C_BPartner_ID.
+ * [2] Class fields with the p_ prefix will be matched automatically. Example:
+ * @Parameter Integer p_C_BPartner_ID will match a parameter named C_BPartner_ID.
+ * [3] Fields with their names matching metadata names after stripping the "_" character. Example:
+ * @Parameter Integer cBPartnerId will match a parameter named C_BPartner_ID.
+ * [4] Fields with their names matching exactly their metadata names. Example:
+ * @Parameter Integer C_BPartner_ID will match a parameter named C_BPartner_ID.
+ * @see SvrProcess
+ * @author Saulo Gil
+ */
+@Target(FIELD)
+@Retention(RUNTIME)
+public @interface Parameter {
+
+ /**
+ * Optional parameter name matching its metadata definition.
+ * @see X_AD_Process_Para#getColumnName()
+ * @return
+ */
+ String name() default "";
+}
diff --git a/org.adempiere.base/src/org/compiere/process/SvrProcess.java b/org.adempiere.base/src/org/compiere/process/SvrProcess.java
index 89ff2ff75b..2e5e4f6075 100644
--- a/org.adempiere.base/src/org/compiere/process/SvrProcess.java
+++ b/org.adempiere.base/src/org/compiere/process/SvrProcess.java
@@ -16,17 +16,25 @@
*****************************************************************************/
package org.compiere.process;
+import java.lang.reflect.Field;
import java.lang.reflect.Method;
+import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.Properties;
+import java.util.TreeMap;
import java.util.logging.Level;
+import java.util.stream.Collectors;
+import org.adempiere.base.annotation.Parameter;
import org.adempiere.base.event.EventManager;
import org.adempiere.base.event.EventProperty;
import org.adempiere.base.event.IEventManager;
@@ -234,6 +242,7 @@ public abstract class SvrProcess implements ProcessCall
boolean success = true;
try
{
+ autoFillParameters();
prepare();
// event before process
@@ -719,4 +728,92 @@ public abstract class SvrProcess implements ProcessCall
processUI.statusUpdate(message);
}
}
+
+ /**
+ * Attempts to initialize class fields having the {@link Parameter} annotation
+ * with the values received by this process instance.
+ */
+ private void autoFillParameters(){
+ Map map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+
+ // detects annotated fields in this class and its super classes
+ Class> target = getClass();
+ while(target != null && !target.equals(SvrProcess.class)) {
+ for (Field field: getFieldsWithParameters(target)) {
+ field.setAccessible(true);
+ Parameter pa = field.getAnnotation(Parameter.class);
+ if(map.containsValue(field))
+ continue;
+ String name = pa.name().isEmpty() ? field.getName() : pa.name();
+ map.put(name.toLowerCase(), field);
+ }
+ target = target.getSuperclass();
+ }
+
+ if(map.size()==0)
+ return;
+
+ for(ProcessInfoParameter parameter : getParameter()){
+ String name = parameter.getParameterName().trim().toLowerCase();
+ Field field = map.get(name);
+ Field toField = map.containsKey(name + "_to") ? map.get(name + "_to") : null;
+
+ // try to match fields using the "p_" prefix convention
+ if(field==null) {
+ String candidate = "p_" + name;
+ field = map.get(candidate);
+ toField = map.containsKey(candidate + "_to") ? map.get(candidate + "_to") : null;
+ }
+
+ // try to match fields with same name as metadata declaration after stripping "_"
+ if(field==null) {
+ String candidate = name.replace("_", "");
+ field = map.get(candidate);
+ toField = map.containsKey(candidate + "to") ? map.get(candidate + "to") : null;
+ }
+
+ if(field==null)
+ continue;
+
+ Type type = field.getType();
+ try{
+ if (type.equals(Integer.TYPE) || type.equals(Integer.class)) {
+ field.set(this, parameter.getParameterAsInt());
+ if(parameter.getParameter_To()!=null && toField != null)
+ toField.set(this, parameter.getParameter_ToAsInt());
+ } else if (type.equals(String.class)) {
+ field.set(this, (String) parameter.getParameter());
+ } else if (type.equals(java.sql.Timestamp.class)) {
+ field.set(this, (Timestamp) parameter.getParameter());
+ if(parameter.getParameter_To()!=null && toField != null)
+ toField.set(this, (Timestamp) parameter.getParameter_To());
+ } else if (type.equals(BigDecimal.class)) {
+ field.set(this, (BigDecimal) parameter.getParameter());
+ } else if (type.equals(boolean.class) || type.equals(Boolean.class)) {
+ Object tmp = parameter.getParameter();
+ if(tmp instanceof String && tmp != null)
+ field.set(this, "Y".equals(tmp));
+ } else {
+ continue;
+ }
+ }catch(Exception e){
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ /**
+ * Tries to find all class attributes having the {@link Parameter} annotation.
+ * @param clazz
+ * @return a list of annotated fields
+ */
+ private List getFieldsWithParameters(Class> clazz) {
+ if (clazz != null)
+ return Arrays.stream(clazz.getDeclaredFields())
+ .filter(f -> f.getAnnotation(Parameter.class) != null)
+ .collect(Collectors.toList());
+
+ return Collections.emptyList();
+ }
+
} // SvrProcess