Thing actions: Process @ActionOutput for actions with single return value & Enforce proper annotations (#4430)

See discussion in https://github.com/openhab/openhab-addons/issues/17504#issuecomment-2439906483.

This adds processing of the ActionOutput annotation for Thing actions with a single return value, which allows providing a label for use in the UI.
The output name for those actions is "result", which is now the default value in the @ActionOutput annotation. If a binding overrides the default name, a warning is logged.

If a Thing action returns a Map<String, Object> but does not provide the @ActionOutputs annotation, a warning is logged.

Signed-off-by: Florian Hotze <dev@florianhotze.com>
This commit is contained in:
Florian Hotze 2024-10-27 19:53:19 +01:00 committed by GitHub
parent 922a2068c0
commit 7f5fbbb22f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 31 additions and 9 deletions

View File

@ -13,6 +13,7 @@
package org.openhab.core.automation.annotation;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static org.openhab.core.automation.internal.module.handler.AnnotationActionHandler.MODULE_RESULT;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
@ -39,7 +40,7 @@ public @interface ActionOutput {
*
* @return the name of the output parameter
*/
String name();
String name() default MODULE_RESULT;
/**
* Type of the output parameter

View File

@ -42,7 +42,7 @@ import org.slf4j.LoggerFactory;
@NonNullByDefault
public class AnnotationActionHandler extends BaseActionModuleHandler {
private static final String MODULE_RESULT = "result";
public static final String MODULE_RESULT = "result";
private final Logger logger = LoggerFactory.getLogger(AnnotationActionHandler.class);

View File

@ -12,6 +12,8 @@
*/
package org.openhab.core.automation.module.provider;
import static org.openhab.core.automation.internal.module.handler.AnnotationActionHandler.MODULE_RESULT;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
@ -143,17 +145,36 @@ public class AnnotationActionModuleTypeHelper {
return inputs;
}
private Output getOutputFromActionOutputAnnotation(ActionOutput ruleActionOutput, @Nullable String nameOverride) {
return new Output((nameOverride != null ? nameOverride : ruleActionOutput.name()), ruleActionOutput.type(),
ruleActionOutput.label(), ruleActionOutput.description(),
Arrays.stream(ruleActionOutput.tags()).collect(Collectors.toSet()), ruleActionOutput.reference(),
ruleActionOutput.defaultValue());
}
private List<Output> getOutputsFromAction(Method method) {
List<Output> outputs = new ArrayList<>();
// ActionOutputs annotation
if (method.isAnnotationPresent(ActionOutputs.class)) {
for (ActionOutput ruleActionOutput : method.getAnnotationsByType(ActionOutput.class)) {
Output output = new Output(ruleActionOutput.name(), ruleActionOutput.type(), ruleActionOutput.label(),
ruleActionOutput.description(),
Arrays.stream(ruleActionOutput.tags()).collect(Collectors.toSet()),
ruleActionOutput.reference(), ruleActionOutput.defaultValue());
outputs.add(output);
for (ActionOutput ruleActionOutput : method.getAnnotation(ActionOutputs.class).value()) {
outputs.add(getOutputFromActionOutputAnnotation(ruleActionOutput, null));
}
// no ActionOutputs annotation, but a Map<String, Object> return type
} else if (method.getAnnotatedReturnType().toString()
.equals("java.util.Map<java.lang.String, java.lang.Object>")) {
logger.warn(
"Method {}::{} returns a Map<String, Object> but is not annotated with ActionOutputs. This should be fixed in the binding.",
method.getDeclaringClass().getSimpleName(), method.getName());
return outputs;
// no ActionOutputs annotation and no Map<String, Object> return type, but a single ActionOutput annotation
} else if (method.isAnnotationPresent(ActionOutput.class)) {
ActionOutput ruleActionOutput = method.getAnnotation(ActionOutput.class);
if (!ruleActionOutput.name().equals(MODULE_RESULT)) {
logger.warn(
"Method {}::{} has a single output but does not use the default output name in the ActionOutput annotation. This should be fixed in the binding.",
method.getDeclaringClass().getSimpleName(), method.getName());
}
outputs.add(getOutputFromActionOutputAnnotation(ruleActionOutput, MODULE_RESULT));
}
return outputs;
}