From 424f373f986247c1cba8ba3bd3491f3d1c2d0a6b Mon Sep 17 00:00:00 2001 From: Joram Barrez Date: Mon, 1 Sep 2014 19:12:23 +0200 Subject: [PATCH] Implementing ACT-2089 : Task sorting on due date needs to place those with due date null after those with a duedate Note that this is implemented in a generic way. If other queries would benefit from nulls first/last it could easily be added now. --- .../activiti/engine/impl/AbstractQuery.java | 80 ++++++++++- .../org/activiti/engine/impl/ServiceImpl.java | 12 ++ .../activiti/engine/impl/TaskQueryImpl.java | 19 ++- .../activiti/engine/impl/TaskServiceImpl.java | 11 +- .../cfg/ProcessEngineConfigurationImpl.java | 59 ++++---- .../org/activiti/engine/task/TaskQuery.java | 17 ++- .../engine/test/api/task/TaskDueDateTest.java | 130 ++++++++++++++++++ .../engine/test/api/task/TaskQueryTest.java | 8 ++ .../test/api/task/TaskVariablesTest.java | 41 ++++++ 9 files changed, 342 insertions(+), 35 deletions(-) create mode 100644 modules/activiti-engine/src/test/java/org/activiti/engine/test/api/task/TaskDueDateTest.java diff --git a/modules/activiti-engine/src/main/java/org/activiti/engine/impl/AbstractQuery.java b/modules/activiti-engine/src/main/java/org/activiti/engine/impl/AbstractQuery.java index 79bdf18547..24c1bd65d2 100644 --- a/modules/activiti-engine/src/main/java/org/activiti/engine/impl/AbstractQuery.java +++ b/modules/activiti-engine/src/main/java/org/activiti/engine/impl/AbstractQuery.java @@ -17,6 +17,7 @@ import java.util.List; import org.activiti.engine.ActivitiException; import org.activiti.engine.ActivitiIllegalArgumentException; +import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.activiti.engine.impl.context.Context; import org.activiti.engine.impl.db.ListQueryParameterObject; import org.activiti.engine.impl.interceptor.Command; @@ -41,15 +42,25 @@ public abstract class AbstractQuery, U> extends ListQueryPa private static enum ResultType { LIST, LIST_PAGE, SINGLE_RESULT, COUNT } + protected transient CommandExecutor commandExecutor; protected transient CommandContext commandContext; + + protected String databaseType; + protected String orderBy; protected ResultType resultType; protected QueryProperty orderProperty; - + + public static enum NullHandlingOnOrder { + NULLS_FIRST, NULLS_LAST + } + + protected NullHandlingOnOrder nullHandlingOnOrder; + protected AbstractQuery() { parameter = this; } @@ -72,6 +83,13 @@ public abstract class AbstractQuery, U> extends ListQueryPa this.orderProperty = property; return (T) this; } + + @SuppressWarnings("unchecked") + public T orderBy(QueryProperty property, NullHandlingOnOrder nullHandlingOnOrder) { + orderBy(property); + this.nullHandlingOnOrder = nullHandlingOnOrder; + return (T) this; + } public T asc() { return direction(Direction.ASCENDING); @@ -86,8 +104,9 @@ public abstract class AbstractQuery, U> extends ListQueryPa if (orderProperty==null) { throw new ActivitiIllegalArgumentException("You should call any of the orderBy methods first before specifying a direction"); } - addOrder(orderProperty.getName(), direction.getName()); + addOrder(orderProperty.getName(), direction.getName(), nullHandlingOnOrder); orderProperty = null; + nullHandlingOnOrder = null; return (T) this; } @@ -164,13 +183,55 @@ public abstract class AbstractQuery, U> extends ListQueryPa return null; } - protected void addOrder(String column, String sortOrder) { - if (orderBy==null) { + protected void addOrder(String column, String sortOrder, NullHandlingOnOrder nullHandlingOnOrder) { + + if (orderBy==null) { orderBy = ""; } else { orderBy = orderBy+", "; } - orderBy = orderBy+column+" "+sortOrder; + + String defaultOrderByClause = column + " "+sortOrder; + + if (nullHandlingOnOrder != null) { + + if (nullHandlingOnOrder.equals(NullHandlingOnOrder.NULLS_FIRST)) { + + if (ProcessEngineConfigurationImpl.DATABASE_TYPE_H2.equals(databaseType) + || ProcessEngineConfigurationImpl.DATABASE_TYPE_POSTGRES.equals(databaseType) + || ProcessEngineConfigurationImpl.DATABASE_TYPE_ORACLE.equals(databaseType)) { + orderBy = orderBy + defaultOrderByClause + " NULLS FIRST"; + } else if (ProcessEngineConfigurationImpl.DATABASE_TYPE_MYSQL.equals(databaseType)) { + orderBy = orderBy + "isnull(" + column +") desc," + defaultOrderByClause; + } else if (ProcessEngineConfigurationImpl.DATABASE_TYPE_DB2.equals(databaseType) + || ProcessEngineConfigurationImpl.DATABASE_TYPE_MSSQL.equals(databaseType)) { + orderBy = orderBy + "case when " + column + " is null then 1 else 0 end," + defaultOrderByClause; + } else { + orderBy = orderBy + defaultOrderByClause; + } + + + } else if (nullHandlingOnOrder.equals(NullHandlingOnOrder.NULLS_LAST)) { + + if (ProcessEngineConfigurationImpl.DATABASE_TYPE_H2.equals(databaseType) + || ProcessEngineConfigurationImpl.DATABASE_TYPE_POSTGRES.equals(databaseType) + || ProcessEngineConfigurationImpl.DATABASE_TYPE_ORACLE.equals(databaseType)) { + orderBy = orderBy + column + " "+sortOrder + " NULLS LAST"; + } else if (ProcessEngineConfigurationImpl.DATABASE_TYPE_MYSQL.equals(databaseType)) { + orderBy = orderBy + "order by isnull(" + column +") asc," + defaultOrderByClause; + } else if (ProcessEngineConfigurationImpl.DATABASE_TYPE_DB2.equals(databaseType) + || ProcessEngineConfigurationImpl.DATABASE_TYPE_MSSQL.equals(databaseType)) { + orderBy = orderBy + "case when " + column + " is null then 0 else 1 end," + defaultOrderByClause; + } else { + orderBy = orderBy + defaultOrderByClause; + } + + } + + } else { + orderBy = orderBy + defaultOrderByClause; + } + } public String getOrderBy() { @@ -180,4 +241,13 @@ public abstract class AbstractQuery, U> extends ListQueryPa return orderBy; } } + + public String getDatabaseType() { + return databaseType; + } + + public void setDatabaseType(String databaseType) { + this.databaseType = databaseType; + } + } diff --git a/modules/activiti-engine/src/main/java/org/activiti/engine/impl/ServiceImpl.java b/modules/activiti-engine/src/main/java/org/activiti/engine/impl/ServiceImpl.java index 34696b3441..80eefd2ec4 100644 --- a/modules/activiti-engine/src/main/java/org/activiti/engine/impl/ServiceImpl.java +++ b/modules/activiti-engine/src/main/java/org/activiti/engine/impl/ServiceImpl.java @@ -12,14 +12,26 @@ */ package org.activiti.engine.impl; +import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.activiti.engine.impl.interceptor.CommandExecutor; /** * @author Tom Baeyens + * @author Joram Barrez */ public class ServiceImpl { + + protected ProcessEngineConfigurationImpl processEngineConfiguration; + + public ServiceImpl() { + + } + + public ServiceImpl(ProcessEngineConfigurationImpl processEngineConfiguration) { + this.processEngineConfiguration = processEngineConfiguration; + } protected CommandExecutor commandExecutor; diff --git a/modules/activiti-engine/src/main/java/org/activiti/engine/impl/TaskQueryImpl.java b/modules/activiti-engine/src/main/java/org/activiti/engine/impl/TaskQueryImpl.java index b7f0c58f56..921806bd3f 100644 --- a/modules/activiti-engine/src/main/java/org/activiti/engine/impl/TaskQueryImpl.java +++ b/modules/activiti-engine/src/main/java/org/activiti/engine/impl/TaskQueryImpl.java @@ -37,6 +37,7 @@ import org.activiti.engine.task.TaskQuery; public class TaskQueryImpl extends AbstractVariableQueryImpl implements TaskQuery { private static final long serialVersionUID = 1L; + protected String taskId; protected String name; protected String nameLike; @@ -87,7 +88,7 @@ public class TaskQueryImpl extends AbstractVariableQueryImpl im protected boolean bothCandidateAndAssigned = false; protected boolean orActive; protected TaskQueryImpl orQueryObject; - + public TaskQueryImpl() { } @@ -98,7 +99,12 @@ public class TaskQueryImpl extends AbstractVariableQueryImpl im public TaskQueryImpl(CommandExecutor commandExecutor) { super(commandExecutor); } - + + public TaskQueryImpl(CommandExecutor commandExecutor, String databaseType) { + super(commandExecutor); + this.databaseType = databaseType; + } + public TaskQueryImpl taskId(String taskId) { if (taskId == null) { throw new ActivitiIllegalArgumentException("Task id is null"); @@ -908,6 +914,15 @@ public class TaskQueryImpl extends AbstractVariableQueryImpl im return orderBy(TaskQueryProperty.DUE_DATE); } + public TaskQuery orderByDueDateNullsFirst() { + return orderBy(TaskQueryProperty.DUE_DATE, NullHandlingOnOrder.NULLS_FIRST); + } + + @Override + public TaskQuery orderByDueDateNullsLast() { + return orderBy(TaskQueryProperty.DUE_DATE, NullHandlingOnOrder.NULLS_LAST); + } + @Override public TaskQuery orderByTenantId() { return orderBy(TaskQueryProperty.TENANT_ID); diff --git a/modules/activiti-engine/src/main/java/org/activiti/engine/impl/TaskServiceImpl.java b/modules/activiti-engine/src/main/java/org/activiti/engine/impl/TaskServiceImpl.java index da88acac25..b82e01598f 100644 --- a/modules/activiti-engine/src/main/java/org/activiti/engine/impl/TaskServiceImpl.java +++ b/modules/activiti-engine/src/main/java/org/activiti/engine/impl/TaskServiceImpl.java @@ -22,6 +22,7 @@ import java.util.Map; import org.activiti.engine.ActivitiIllegalArgumentException; import org.activiti.engine.TaskService; +import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl; import org.activiti.engine.impl.cmd.AddCommentCmd; import org.activiti.engine.impl.cmd.AddIdentityLinkCmd; import org.activiti.engine.impl.cmd.ClaimTaskCmd; @@ -71,6 +72,14 @@ import org.activiti.engine.task.TaskQuery; * @author Joram Barrez */ public class TaskServiceImpl extends ServiceImpl implements TaskService { + + public TaskServiceImpl() { + + } + + public TaskServiceImpl(ProcessEngineConfigurationImpl processEngineConfiguration) { + super(processEngineConfiguration); + } public Task newTask() { return newTask(null); @@ -195,7 +204,7 @@ public class TaskServiceImpl extends ServiceImpl implements TaskService { } public TaskQuery createTaskQuery() { - return new TaskQueryImpl(commandExecutor); + return new TaskQueryImpl(commandExecutor, processEngineConfiguration.getDatabaseType()); } public NativeTaskQuery createNativeTaskQuery() { diff --git a/modules/activiti-engine/src/main/java/org/activiti/engine/impl/cfg/ProcessEngineConfigurationImpl.java b/modules/activiti-engine/src/main/java/org/activiti/engine/impl/cfg/ProcessEngineConfigurationImpl.java index 5bdf4cad35..f6035e1576 100755 --- a/modules/activiti-engine/src/main/java/org/activiti/engine/impl/cfg/ProcessEngineConfigurationImpl.java +++ b/modules/activiti-engine/src/main/java/org/activiti/engine/impl/cfg/ProcessEngineConfigurationImpl.java @@ -248,7 +248,7 @@ public abstract class ProcessEngineConfigurationImpl extends ProcessEngineConfig protected RuntimeService runtimeService = new RuntimeServiceImpl(); protected HistoryService historyService = new HistoryServiceImpl(); protected IdentityService identityService = new IdentityServiceImpl(); - protected TaskService taskService = new TaskServiceImpl(); + protected TaskService taskService = new TaskServiceImpl(this); protected FormService formService = new FormServiceImpl(); protected ManagementService managementService = new ManagementServiceImpl(); @@ -591,34 +591,41 @@ public abstract class ProcessEngineConfigurationImpl extends ProcessEngineConfig } protected static Properties databaseTypeMappings = getDefaultDatabaseTypeMappings(); + + public static final String DATABASE_TYPE_H2 = "h2"; + public static final String DATABASE_TYPE_MYSQL = "mysql"; + public static final String DATABASE_TYPE_ORACLE = "oracle"; + public static final String DATABASE_TYPE_POSTGRES = "postgres"; + public static final String DATABASE_TYPE_MSSQL = "mssql"; + public static final String DATABASE_TYPE_DB2 = "db2"; protected static Properties getDefaultDatabaseTypeMappings() { Properties databaseTypeMappings = new Properties(); - databaseTypeMappings.setProperty("H2","h2"); - databaseTypeMappings.setProperty("MySQL","mysql"); - databaseTypeMappings.setProperty("Oracle","oracle"); - databaseTypeMappings.setProperty("PostgreSQL","postgres"); - databaseTypeMappings.setProperty("Microsoft SQL Server","mssql"); - databaseTypeMappings.setProperty("DB2","db2"); - databaseTypeMappings.setProperty("DB2","db2"); - databaseTypeMappings.setProperty("DB2/NT","db2"); - databaseTypeMappings.setProperty("DB2/NT64","db2"); - databaseTypeMappings.setProperty("DB2 UDP","db2"); - databaseTypeMappings.setProperty("DB2/LINUX","db2"); - databaseTypeMappings.setProperty("DB2/LINUX390","db2"); - databaseTypeMappings.setProperty("DB2/LINUXX8664","db2"); - databaseTypeMappings.setProperty("DB2/LINUXZ64","db2"); - databaseTypeMappings.setProperty("DB2/400 SQL","db2"); - databaseTypeMappings.setProperty("DB2/6000","db2"); - databaseTypeMappings.setProperty("DB2 UDB iSeries","db2"); - databaseTypeMappings.setProperty("DB2/AIX64","db2"); - databaseTypeMappings.setProperty("DB2/HPUX","db2"); - databaseTypeMappings.setProperty("DB2/HP64","db2"); - databaseTypeMappings.setProperty("DB2/SUN","db2"); - databaseTypeMappings.setProperty("DB2/SUN64","db2"); - databaseTypeMappings.setProperty("DB2/PTX","db2"); - databaseTypeMappings.setProperty("DB2/2","db2"); - databaseTypeMappings.setProperty("DB2 UDB AS400", "db2"); + databaseTypeMappings.setProperty("H2", DATABASE_TYPE_H2); + databaseTypeMappings.setProperty("MySQL", DATABASE_TYPE_MYSQL); + databaseTypeMappings.setProperty("Oracle", DATABASE_TYPE_ORACLE); + databaseTypeMappings.setProperty("PostgreSQL", DATABASE_TYPE_POSTGRES); + databaseTypeMappings.setProperty("Microsoft SQL Server", DATABASE_TYPE_MSSQL); + databaseTypeMappings.setProperty(DATABASE_TYPE_DB2,DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty(DATABASE_TYPE_DB2,DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/NT",DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/NT64",DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2 UDP",DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/LINUX",DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/LINUX390",DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/LINUXX8664",DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/LINUXZ64",DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/400 SQL",DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/6000",DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2 UDB iSeries",DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/AIX64",DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/HPUX",DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/HP64",DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/SUN",DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/SUN64",DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/PTX",DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2/2",DATABASE_TYPE_DB2); + databaseTypeMappings.setProperty("DB2 UDB AS400", DATABASE_TYPE_DB2); return databaseTypeMappings; } diff --git a/modules/activiti-engine/src/main/java/org/activiti/engine/task/TaskQuery.java b/modules/activiti-engine/src/main/java/org/activiti/engine/task/TaskQuery.java index c9ce228397..7c352da09e 100644 --- a/modules/activiti-engine/src/main/java/org/activiti/engine/task/TaskQuery.java +++ b/modules/activiti-engine/src/main/java/org/activiti/engine/task/TaskQuery.java @@ -453,9 +453,24 @@ public interface TaskQuery extends Query{ /** Order by execution id (needs to be followed by {@link #asc()} or {@link #desc()}). */ TaskQuery orderByExecutionId(); - /** Order by due date (needs to be followed by {@link #asc()} or {@link #desc()}). */ + /** + * Order by due date (needs to be followed by {@link #asc()} or {@link #desc()}). + * This will use the default handling of null values of the used database. + */ TaskQuery orderByDueDate(); + /** + * Order by due date (needs to be followed by {@link #asc()} or {@link #desc()}). + * If any of the tasks have null for the due date, these will be first in the result. + */ + TaskQuery orderByDueDateNullsFirst(); + + /** + * Order by due date (needs to be followed by {@link #asc()} or {@link #desc()}). + * If any of the tasks have null for the due date, these will be last in the result. + */ + TaskQuery orderByDueDateNullsLast(); + /** Order by tenant id (needs to be followed by {@link #asc()} or {@link #desc()}). */ TaskQuery orderByTenantId(); } diff --git a/modules/activiti-engine/src/test/java/org/activiti/engine/test/api/task/TaskDueDateTest.java b/modules/activiti-engine/src/test/java/org/activiti/engine/test/api/task/TaskDueDateTest.java new file mode 100644 index 0000000000..a0eefd4af4 --- /dev/null +++ b/modules/activiti-engine/src/test/java/org/activiti/engine/test/api/task/TaskDueDateTest.java @@ -0,0 +1,130 @@ +/* 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.activiti.engine.test.api.task; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.activiti.engine.ActivitiException; +import org.activiti.engine.ActivitiIllegalArgumentException; +import org.activiti.engine.impl.history.HistoryLevel; +import org.activiti.engine.impl.persistence.entity.TaskEntity; +import org.activiti.engine.impl.persistence.entity.VariableInstanceEntity; +import org.activiti.engine.impl.test.PluggableActivitiTestCase; +import org.activiti.engine.runtime.ProcessInstance; +import org.activiti.engine.task.DelegationState; +import org.activiti.engine.task.Task; +import org.activiti.engine.task.TaskQuery; +import org.activiti.engine.test.Deployment; + +/** + * @author Joram Barrez + * @author Frederik Heremans + * @author Falko Menge + */ +public class TaskDueDateTest extends PluggableActivitiTestCase { + + @Override + protected void tearDown() throws Exception { + + for (Task task : taskService.createTaskQuery().list()) { + taskService.deleteTask(task.getId(), true); + } + + super.tearDown(); + } + + /** + * See http://jira.codehaus.org/browse/ACT-2089 + */ + public void testDueDateSortingWithNulls() { + Date now = processEngineConfiguration.getClock().getCurrentTime(); + + // 4 tasks with a due date + Task task0 = createTask("task0", new Date(now.getTime() + (4L * 7L * 24L * 60L * 60L * 1000L))); // 4 weeks in future + Task task1 = createTask("task1", new Date(now.getTime() + (2 * 24L * 60L * 60L * 1000L))); // 2 days in future + Task task2 = createTask("task2", new Date(now.getTime() + (7L * 24L * 60L * 60L * 1000L))); // 1 week in future + Task task3 = createTask("task3", new Date(now.getTime() + (24L * 60L * 60L * 1000L))); // 1 day in future + + // 2 tasks without a due date + createTask("task4", null); + createTask("task5", null); + + assertEquals(6, taskService.createTaskQuery().count()); + + // Sorting on due date asc should put the nulls at the end + List tasks = taskService.createTaskQuery().orderByDueDateNullsLast().asc().list(); + + for (int i=0; i<4; i++) { + assertNotNull(tasks.get(i).getDueDate()); + } + + assertEquals("task3", tasks.get(0).getName()); + assertEquals("task1", tasks.get(1).getName()); + assertEquals("task2", tasks.get(2).getName()); + assertEquals("task0", tasks.get(3).getName()); + assertNull(tasks.get(4).getDueDate()); + assertNull(tasks.get(5).getDueDate()); + + // The same, but now desc + tasks = taskService.createTaskQuery().orderByDueDateNullsLast().desc().list(); + + for (int i=0; i<4; i++) { + assertNotNull(tasks.get(i).getDueDate()); + } + + assertEquals("task0", tasks.get(0).getName()); + assertEquals("task2", tasks.get(1).getName()); + assertEquals("task1", tasks.get(2).getName()); + assertEquals("task3", tasks.get(3).getName()); + assertNull(tasks.get(4).getDueDate()); + assertNull(tasks.get(5).getDueDate()); + + // The same but now nulls first + tasks = taskService.createTaskQuery().orderByDueDateNullsFirst().asc().list(); + + assertNull(tasks.get(0).getDueDate()); + assertNull(tasks.get(1).getDueDate()); + assertEquals("task3", tasks.get(2).getName()); + assertEquals("task1", tasks.get(3).getName()); + assertEquals("task2", tasks.get(4).getName()); + assertEquals("task0", tasks.get(5).getName()); + + // And now desc + tasks = taskService.createTaskQuery().orderByDueDateNullsFirst().desc().list(); + + assertNull(tasks.get(0).getDueDate()); + assertNull(tasks.get(1).getDueDate()); + assertEquals("task0", tasks.get(2).getName()); + assertEquals("task2", tasks.get(3).getName()); + assertEquals("task1", tasks.get(4).getName()); + assertEquals("task3", tasks.get(5).getName()); + + } + + private Task createTask(String name, Date dueDate) { + Task task = taskService.newTask(); + task.setName(name); + task.setDueDate(dueDate); + taskService.saveTask(task); + return task; + } + +} diff --git a/modules/activiti-engine/src/test/java/org/activiti/engine/test/api/task/TaskQueryTest.java b/modules/activiti-engine/src/test/java/org/activiti/engine/test/api/task/TaskQueryTest.java index c903fbb61f..874200e3e9 100644 --- a/modules/activiti-engine/src/test/java/org/activiti/engine/test/api/task/TaskQueryTest.java +++ b/modules/activiti-engine/src/test/java/org/activiti/engine/test/api/task/TaskQueryTest.java @@ -2251,6 +2251,14 @@ public class TaskQueryTest extends PluggableActivitiTestCase { .deploymentId("invalid").count()); } + private Task createTask(String name, Date dueDate) { + Task task = taskService.newTask(); + task.setName(name); + task.setDueDate(dueDate); + taskService.saveTask(task); + return task; + } + /** * Generates some test tasks. - 6 tasks where kermit is a candidate - 1 tasks * where gonzo is assignee - 2 tasks assigned to management group - 2 tasks diff --git a/modules/activiti-engine/src/test/java/org/activiti/engine/test/api/task/TaskVariablesTest.java b/modules/activiti-engine/src/test/java/org/activiti/engine/test/api/task/TaskVariablesTest.java index a394f0c25e..b68920e3ab 100644 --- a/modules/activiti-engine/src/test/java/org/activiti/engine/test/api/task/TaskVariablesTest.java +++ b/modules/activiti-engine/src/test/java/org/activiti/engine/test/api/task/TaskVariablesTest.java @@ -13,6 +13,7 @@ package org.activiti.engine.test.api.task; +import java.io.Serializable; import java.util.HashMap; import java.util.Map; @@ -87,4 +88,44 @@ public class TaskVariablesTest extends PluggableActivitiTestCase { assertEquals(expectedVariables, runtimeService.getVariables(processInstanceId)); assertEquals(expectedVariables, runtimeService.getVariablesLocal(processInstanceId)); } + + public void testSerializableTaskVariable() { + Task task = taskService.newTask(); + task.setName("MyTask"); + taskService.saveTask(task); + + // Set variable + Map vars = new HashMap(); + MyVariable myVariable = new MyVariable("Hello world"); + vars.put("theVar", myVariable); + taskService.setVariables(task.getId(), vars); + + // Fetch variable + MyVariable variable = (MyVariable) taskService.getVariable(task.getId(), "theVar"); + assertEquals("Hello world", variable.getValue()); + + // Cleanup + taskService.deleteTask(task.getId(), true); + } + + public static class MyVariable implements Serializable { + + private String value; + + public MyVariable(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + + + } + } -- GitLab