]> git.basschouten.com Git - openhab-addons.git/blob
364448d70fc06f0ef2fa7724ee017275ec2be41d
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.transform.jsonpath.internal;
14
15 import java.util.List;
16 import java.util.stream.Collectors;
17
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;
26
27 import com.jayway.jsonpath.InvalidJsonException;
28 import com.jayway.jsonpath.InvalidPathException;
29 import com.jayway.jsonpath.JsonPath;
30 import com.jayway.jsonpath.PathNotFoundException;
31
32 /**
33  * <p>
34  * The implementation of {@link TransformationService} which transforms the input by JSonPath Expressions.
35  *
36  * @author GaĆ«l L'hopital
37  * @author Sebastian Janzen
38  *
39  */
40 @NonNullByDefault
41 @Component(property = { "openhab.transform=JSONPATH" })
42 public class JSonPathTransformationService implements TransformationService {
43
44     private final Logger logger = LoggerFactory.getLogger(JSonPathTransformationService.class);
45
46     /**
47      * Transforms the input <code>source</code> by JSonPath expression.
48      *
49      * @param jsonPathExpression 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}.
53      */
54     @Override
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");
58         }
59
60         logger.debug("about to transform '{}' by the function '{}'", source, jsonPathExpression);
61
62         if (source.isBlank()) {
63             // return null if source is empty/blank, JSONPath will throw an IAE on empty input strings
64             return null;
65         }
66         try {
67             Object transformationResult = JsonPath.read(source, jsonPathExpression);
68             logger.debug("transformation resulted in '{}'", transformationResult);
69             if (transformationResult == null) {
70                 return null;
71             } else if (transformationResult instanceof List list) {
72                 return flattenList(list);
73             } else {
74                 return transformationResult.toString();
75             }
76         } catch (PathNotFoundException e) {
77             throw new TransformationException("Invalid path '" + jsonPathExpression + "' in '" + source + "'");
78         } catch (InvalidPathException | InvalidJsonException e) {
79             throw new TransformationException("An error occurred while transforming JSON expression.", e);
80         }
81     }
82
83     private String flattenList(List<?> list) {
84         if (list.size() == 1) {
85             return list.get(0).toString();
86         }
87         if (list.size() > 1) {
88             if (list.get(0) instanceof Number || list.get(0) instanceof Boolean) {
89                 return createNumberList(list);
90             } else if (list.get(0) instanceof String) {
91                 return createStringList(list);
92             }
93             logger.warn(
94                     "JsonPath expressions with more than one result are only supported for Boolean, Number and String data types, please adapt your selector. Result: {}",
95                     list);
96         }
97         return UnDefType.NULL.toFullString();
98     }
99
100     private String createNumberList(List<?> list) {
101         return list.stream().map(n -> String.valueOf(n)).collect(Collectors.joining(", ", "[", "]"));
102     }
103
104     private String createStringList(List<?> list) {
105         return list.stream().map(n -> "\"" + String.valueOf(n) + "\"").collect(Collectors.joining(", ", "[", "]"));
106     }
107 }