Note: This is a clone of my original post located in the wrong forum: How to update task property of type NodeRef using REST API?
Hi,
I'm working on a project which integrates with Alfresco v4.2.e and Activiti v5.13.
I use the REST API to query for tasks through the task-instance service.
When a property is a (collection of) NodeRef, It returns a (collection of) string ("workspace://....").
When I try to update this property, Alfresco throws a ClassCastException saying that String cannot be cast to NodeRef.
I found this bug on your jira https://community.alfresco.com/external-link.jspa?url=https%3A%2F%2Fissues.alfresco.com%2Fjira%2Fbro... which seems to be related to my problem but in the other direction. Is my problem a bug? Is this a bug fixed in the v4.2.f? Did I do something wrong?
Anyway I decided to try the activiti-rest webapp to query directly Activiti. So I searched the war for the 5.13.
Unfortunately the Activiti website doesn't provide a long history of binaries. I had to build the war using the sources from github. When I deployed the compiled war to a Tomcat and tried to get variables through the runtime/tasks service, It throws a ActivitiException "unknown variable type name alfrescoScriptNodeList". Indeed in some Maven repo I've seen some Activiti jars suffixed by "alf". Did I built the wrong war? Is there a fork of the project?
Finally I could write a webscript in Alfresco using the Alfresco Java API but it would be the last option...
Sorry for the length of this text and thanks in advance for your answers.
No one has an answer? I can't imagine I'm the only one who would like to update a nodeRef inside a task using REST...
It isn't really clear what you are trying to do.
That might help people assist you.
You're right I missed some crucial information. My apologies
I use the Workflow repository from the Alfresco Community Edition 4.2.e Rest API, documented here: Workflow | Alfresco Documentation
To get a specific workflow instance, I use the endpoint documented here: Get workflow instance | Alfresco Documentation. Some task instances of a workflow instance have a property of type NodeRef.
In the JSON response, a NodeRef property is represented as follow:
"taskPropertyName":
[
"workspace:\/\/SpacesStore\/5f654948-8a55-4b46-8bb6-9b8e5db7cdec"
]
Now I want to update some properties of a task instance. For that I use the endpoint documented here: Updates workflow task instance | Alfresco Documentation.
The task instance is well updated except if I include a property of type NodeRef.
In that case I receive a status code 500 from the Alfresco REST API. When I check the logs of Alfresco, I see this stacktrace:
Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to org.alfresco.service.cmr.repository.NodeRef
at org.alfresco.repo.workflow.activiti.ActivitiNodeConverter.convertNodes(ActivitiNodeConverter.java:59)
at org.alfresco.repo.workflow.AbstractWorkflowNodeConverter.convertNodes(AbstractWorkflowNodeConverter.java:71)
at org.alfresco.repo.workflow.AbstractWorkflowNodeConverter.convertNodes(AbstractWorkflowNodeConverter.java:47)
at org.alfresco.repo.workflow.AbstractWorkflowPropertyHandler.convertAssociationValue(AbstractWorkflowPropertyHandler.java:106)
at org.alfresco.repo.workflow.AbstractWorkflowPropertyHandler.handleAssociation(AbstractWorkflowPropertyHandler.java:60)
at org.alfresco.repo.workflow.AbstractWorkflowPropertyHandler.handleDefaultProperty(AbstractWorkflowPropertyHandler.java:166)
at org.alfresco.repo.workflow.DefaultWorkflowPropertyHandler.handleProperty(DefaultWorkflowPropertyHandler.java:38)
at org.alfresco.repo.workflow.WorkflowPropertyHandlerRegistry.handleVariablesToSet(WorkflowPropertyHandlerRegistry.java:75)
at org.alfresco.repo.workflow.activiti.properties.ActivitiPropertyConverter.setTaskProperties(ActivitiPropertyConverter.java:789)
at org.alfresco.repo.workflow.activiti.properties.ActivitiPropertyConverter.updateTask(ActivitiPropertyConverter.java:1050)
at org.alfresco.repo.workflow.activiti.ActivitiWorkflowEngine.updateTask(ActivitiWorkflowEngine.java:2167)
at org.alfresco.repo.workflow.WorkflowServiceImpl.updateTask(WorkflowServiceImpl.java:951)
In the PUT HTTP method, I set the property of type NodeRef as follow:
"taskPropertyName":["workspace://SpacesStore/f7be95e4-3b0b-4519-bdb6-06c2dd9685cf"]
I talked about the Activiti REST API as a workaround: I installed it and configured with the same database as the Activiti bundled with Alfresco to see if I could update task instances by this way. But it's not a good idea.
I hope I have been clearer and thanks for your help.
As a workaround I ended up writing a Webscript which do the same as the Alfresco one but with NodeRef handling.
I'ts a bit dirty as I had to parse the string to see if it starts with "workspace://.."
Anyway I'm always interested if someone has the solution or a better workaround.
Here's the code :
public class UpdateTaskProperties extends AbstractWebScript {
private static final String TASK_ID_PARAM = "taskId";
private static Logger LOGGER = LoggerFactory.getLogger(UpdateTaskProperties.class);
private final ObjectMapper objectMapper = new ObjectMapper();
private final NodeRefObjectMapper nodeRefObjectMapper = new NodeRefObjectMapper();
public UpdateTaskProperties() {
}
@Override
public void execute(WebScriptRequest request, WebScriptResponse response) throws IOException {
String taskId = getTaskIdIn(request);
Map<String, Object> properties = objectMapper.readValue(request.getContent().getReader(), Map.class);
Map<String, Object> finalProperties = collectCastedPropertiesFrom(properties);
LOGGER.debug("Updating " + finalProperties.size() + " properties of task " + taskId + "...");
taskService.setVariablesLocal(taskId, finalProperties);
LOGGER.info("Updated " + finalProperties.size() + " properties of task " + taskId);
}
private String getTaskIdIn(WebScriptRequest request) {
String taskId = request.getParameter(TASK_ID_PARAM);
isTrue(isNotBlank(taskId), "Invalid task id");
return taskId;
}
private Map<String, Object> collectCastedPropertiesFrom(Map<String, Object> properties) {
Map<String, Object> finalProperties = newHashMap();
for (String propertyName : properties.keySet()) {
Object value = properties.get(propertyName);
if (nodeRefObjectMapper.isNodeRef(value)) {
finalProperties.put(propertyName, nodeRefObjectMapper.readValue(value));
} else if (nodeRefObjectMapper.isNodeRefCollection(value)) {
finalProperties.put(propertyName, nodeRefObjectMapper.readValues(value));
} else {
finalProperties.put(propertyName, value);
}
}
return finalProperties;
}
}
public class NodeRefObjectMapper {
private static final String WORKSPACE_PREFIX = "workspace://SpacesStore/";
private static final String NOTHING = "";
public NodeRef readValue(Object value) {
isTrue(isNodeRef(value), "Not a NodeRef object");
return toNodeRef((String) value);
}
public Collection<NodeRef> readValues(Object value) {
isTrue(isNodeRefCollection(value), "Not a NodeRef collection object");
return from((Collection<String>) value)
.transform(s -> toNodeRef(s)).toList();
}
public boolean isNodeRef(Object value) {
return value instanceof String && normalize((String) value).startsWith(WORKSPACE_PREFIX);
}
public boolean isNodeRefCollection(Object value) {
return value instanceof Collection
&& !((Collection) value).isEmpty()
&& isNodeRef(((Collection) value).iterator().next());
}
private NodeRef toNodeRef(String value) {
return new NodeRef(STORE_REF_WORKSPACE_SPACESSTORE, toNodeRefId(value));
}
private String toNodeRefId(String nodeRef) {
return normalize(nodeRef).replace(WORKSPACE_PREFIX, NOTHING);
}
private String normalize(String value) {
return value.replace("\\", "");
}
}
Ask for and offer help to other Alfresco Content Services Users and members of the Alfresco team.
Related links:
By using this site, you are agreeing to allow us to collect and use cookies as outlined in Alfresco’s Cookie Statement and Terms of Use (and you have a legitimate interest in Alfresco and our products, authorizing us to contact you in such methods). If you are not ok with these terms, please do not use this website.