2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.transform.jsonpath.internal;
15 import java.util.List;
16 import java.util.stream.Collectors;
18 import org.eclipse.jdt.annotation.NonNullByDefault;
19 import org.eclipse.jdt.annotation.Nullable;
20 import org.openhab.core.transform.TransformationException;
21 import org.openhab.core.transform.TransformationService;
22 import org.openhab.core.types.UnDefType;
23 import org.osgi.service.component.annotations.Component;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
27 import com.jayway.jsonpath.InvalidJsonException;
28 import com.jayway.jsonpath.InvalidPathException;
29 import com.jayway.jsonpath.JsonPath;
30 import com.jayway.jsonpath.PathNotFoundException;
34 * The implementation of {@link TransformationService} which transforms the input by JSonPath Expressions.
36 * @author Gaƫl L'hopital
37 * @author Sebastian Janzen
41 @Component(property = { "openhab.transform=JSONPATH" })
42 public class JSonPathTransformationService implements TransformationService {
44 private final Logger logger = LoggerFactory.getLogger(JSonPathTransformationService.class);
47 * Transforms the input <code>source</code> by JSonPath expression.
49 * @param function JsonPath expression
50 * @param source String which contains JSON
51 * @throws TransformationException If the JsonPath expression is invalid, an {@link InvalidPathException} is thrown,
52 * which is encapsulated in a {@link TransformationException}.
55 public @Nullable String transform(String jsonPathExpression, String source) throws TransformationException {
56 if (jsonPathExpression == null || source == null) {
57 throw new TransformationException("the given parameters 'JSonPath' and 'source' must not be null");
60 logger.debug("about to transform '{}' by the function '{}'", source, jsonPathExpression);
63 Object transformationResult = JsonPath.read(source, jsonPathExpression);
64 logger.debug("transformation resulted in '{}'", transformationResult);
65 if (transformationResult == null) {
67 } else if (transformationResult instanceof List) {
68 return flattenList((List<?>) transformationResult);
70 return transformationResult.toString();
72 } catch (PathNotFoundException e) {
73 throw new TransformationException("Invalid path '" + jsonPathExpression + "' in '" + source + "'");
74 } catch (InvalidPathException | InvalidJsonException e) {
75 throw new TransformationException("An error occurred while transforming JSON expression.", e);
79 private String flattenList(List<?> list) {
80 if (list.size() == 1) {
81 return list.get(0).toString();
83 if (list.size() > 1) {
84 if (list.get(0) instanceof Number || list.get(0) instanceof Boolean) {
85 return createNumberList(list);
86 } else if (list.get(0) instanceof String) {
87 return createStringList(list);
90 "JsonPath expressions with more than one result are only supported for Boolean, Number and String data types, please adapt your selector. Result: {}",
93 return UnDefType.NULL.toFullString();
96 private String createNumberList(List<?> list) {
97 return list.stream().map(n -> String.valueOf(n)).collect(Collectors.joining(", ", "[", "]"));
100 private String createStringList(List<?> list) {
101 return list.stream().map(n -> "\"" + String.valueOf(n) + "\"").collect(Collectors.joining(", ", "[", "]"));