de.fraunhofer.iosb.ilt.sta.persistence.postgres.PropertyHelper.java Source code

Java tutorial

Introduction

Here is the source code for de.fraunhofer.iosb.ilt.sta.persistence.postgres.PropertyHelper.java

Source

/*
 * Copyright (C) 2016 Fraunhofer Institut IOSB, Fraunhoferstr. 1, D 76131
 * Karlsruhe, Germany.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package de.fraunhofer.iosb.ilt.sta.persistence.postgres;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.querydsl.core.Tuple;
import com.querydsl.core.types.Expression;
import com.querydsl.core.types.Path;
import com.querydsl.core.types.dsl.NumberPath;
import de.fraunhofer.iosb.ilt.sta.deserialize.custom.geojson.GeoJsonDeserializier;
import de.fraunhofer.iosb.ilt.sta.model.Datastream;
import de.fraunhofer.iosb.ilt.sta.model.FeatureOfInterest;
import de.fraunhofer.iosb.ilt.sta.model.HistoricalLocation;
import de.fraunhofer.iosb.ilt.sta.model.Location;
import de.fraunhofer.iosb.ilt.sta.model.MultiDatastream;
import de.fraunhofer.iosb.ilt.sta.model.Observation;
import de.fraunhofer.iosb.ilt.sta.model.ObservedProperty;
import de.fraunhofer.iosb.ilt.sta.model.Sensor;
import de.fraunhofer.iosb.ilt.sta.model.Thing;
import de.fraunhofer.iosb.ilt.sta.model.core.Entity;
import de.fraunhofer.iosb.ilt.sta.model.core.EntitySet;
import de.fraunhofer.iosb.ilt.sta.model.core.EntitySetImpl;
import de.fraunhofer.iosb.ilt.sta.model.ext.TimeInstant;
import de.fraunhofer.iosb.ilt.sta.model.ext.TimeInterval;
import de.fraunhofer.iosb.ilt.sta.model.ext.TimeValue;
import de.fraunhofer.iosb.ilt.sta.model.ext.UnitOfMeasurement;
import de.fraunhofer.iosb.ilt.sta.model.id.LongId;
import de.fraunhofer.iosb.ilt.sta.path.EntityProperty;
import de.fraunhofer.iosb.ilt.sta.path.EntityType;
import de.fraunhofer.iosb.ilt.sta.persistence.QDatastreams;
import de.fraunhofer.iosb.ilt.sta.persistence.QFeatures;
import de.fraunhofer.iosb.ilt.sta.persistence.QHistLocations;
import de.fraunhofer.iosb.ilt.sta.persistence.QLocations;
import de.fraunhofer.iosb.ilt.sta.persistence.QMultiDatastreams;
import de.fraunhofer.iosb.ilt.sta.persistence.QObsProperties;
import de.fraunhofer.iosb.ilt.sta.persistence.QObservations;
import de.fraunhofer.iosb.ilt.sta.persistence.QSensors;
import de.fraunhofer.iosb.ilt.sta.persistence.QThings;
import de.fraunhofer.iosb.ilt.sta.util.GeoHelper;
import java.io.IOException;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.geojson.Polygon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author scf
 */
public class PropertyHelper {

    public static interface entityFromTupleFactory<T extends Entity> {

        /**
         * Creates a T, reading the Tuple with a qObject using no alias.
         *
         * @param tuple The tuple to create the Entity from.
         * @return The Entity created from the Tuple.
         */
        public T create(Tuple tuple);

        /**
         * Get the primary key of the table of the entity this factory
         *
         * @return The primary key of the table of the entity this factory
         * creates, using no alias.
         */
        public NumberPath<Long> getPrimaryKey();

        /**
         * Get the EntityType of the Entities created by this factory.
         *
         * @return The EntityType of the Entities created by this factory.
         */
        public EntityType getEntityType();
    }

    /**
     * The logger for this class.
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(PropertyHelper.class);
    private static final TypeReference<List<String>> TYPE_LIST_STRING = new TypeReference<List<String>>() {
        // Empty on purpose.
    };
    private static final TypeReference<List<UnitOfMeasurement>> TYPE_LIST_UOM = new TypeReference<List<UnitOfMeasurement>>() {
        // Empty on purpose.
    };
    private static final Map<Class<? extends Entity>, entityFromTupleFactory<? extends Entity>> FACTORY_PER_ENTITY = new HashMap<>();

    public static Expression<?>[] getExpressions(Path<?> qPath, Set<EntityProperty> selectedProperties) {
        List<Expression<?>> exprList = new ArrayList<>();
        if (selectedProperties.isEmpty()) {
            PropertyResolver.expressionsForClass(qPath, exprList);
        } else {
            for (EntityProperty property : selectedProperties) {
                PropertyResolver.expressionsForProperty(property, qPath, exprList);
            }
        }
        return exprList.toArray(new Expression<?>[exprList.size()]);
    }

    public static <T extends Entity> EntitySet<T> createSetFromTuples(entityFromTupleFactory<T> factory,
            List<Tuple> tuples, int top) {
        EntitySet<T> entitySet = new EntitySetImpl<>(factory.getEntityType());
        int count = 0;
        for (Tuple tuple : tuples) {
            entitySet.add(factory.create(tuple));
            count++;
            if (count >= top) {
                return entitySet;
            }
        }
        return entitySet;
    }

    public static class DatastreamFactory implements PropertyHelper.entityFromTupleFactory<Datastream> {

        public static final DatastreamFactory withDefaultAlias = new DatastreamFactory(
                new QDatastreams(PathSqlBuilder.ALIAS_PREFIX + "1"));

        private final QDatastreams qInstance;

        public DatastreamFactory(QDatastreams qInstance) {
            this.qInstance = qInstance;
        }

        @Override
        public Datastream create(Tuple tuple) {
            Datastream entity = new Datastream();
            entity.setName(tuple.get(qInstance.name));
            entity.setDescription(tuple.get(qInstance.description));
            Long id = tuple.get(qInstance.id);
            if (id != null) {
                entity.setId(new LongId(tuple.get(qInstance.id)));
            }
            entity.setObservationType(tuple.get(qInstance.observationType));

            String observedArea = tuple.get(qInstance.observedArea.asText());
            if (observedArea != null) {
                try {
                    Polygon polygon = GeoHelper.parsePolygon(observedArea);
                    entity.setObservedArea(polygon);
                } catch (IllegalArgumentException e) {
                    // It's not a polygon, probably a point or a line.
                }
            }
            ObservedProperty op = observedProperyFromId(tuple.get(qInstance.obsPropertyId));
            entity.setObservedProperty(op);

            Timestamp pTimeStart = tuple.get(qInstance.phenomenonTimeStart);
            Timestamp pTimeEnd = tuple.get(qInstance.phenomenonTimeEnd);
            if (pTimeStart != null && pTimeEnd != null) {
                entity.setPhenomenonTime(intervalFromTimes(pTimeStart, pTimeEnd));
            }

            Timestamp rTimeStart = tuple.get(qInstance.resultTimeStart);
            Timestamp rTimeEnd = tuple.get(qInstance.resultTimeEnd);
            if (rTimeStart != null && rTimeEnd != null) {
                entity.setResultTime(intervalFromTimes(rTimeStart, rTimeEnd));
            }

            entity.setSensor(sensorFromId(tuple.get(qInstance.sensorId)));
            entity.setThing(thingFromId(tuple.get(qInstance.thingId)));

            entity.setUnitOfMeasurement(new UnitOfMeasurement(tuple.get(qInstance.unitName),
                    tuple.get(qInstance.unitSymbol), tuple.get(qInstance.unitDefinition)));
            return entity;
        }

        @Override
        public NumberPath<Long> getPrimaryKey() {
            return qInstance.id;
        }

        @Override
        public EntityType getEntityType() {
            return EntityType.Datastream;
        }

    }

    public static class MultiDatastreamFactory implements PropertyHelper.entityFromTupleFactory<MultiDatastream> {

        public static final MultiDatastreamFactory withDefaultAlias = new MultiDatastreamFactory(
                new QMultiDatastreams(PathSqlBuilder.ALIAS_PREFIX + "1"));

        private final QMultiDatastreams qInstance;

        public MultiDatastreamFactory(QMultiDatastreams qInstance) {
            this.qInstance = qInstance;
        }

        @Override
        public MultiDatastream create(Tuple tuple) {
            MultiDatastream entity = new MultiDatastream();
            entity.setName(tuple.get(qInstance.name));
            entity.setDescription(tuple.get(qInstance.description));
            Long id = tuple.get(qInstance.id);
            if (id != null) {
                entity.setId(new LongId(tuple.get(qInstance.id)));
            }

            List<String> observationTypes = jsonToObject(tuple.get(qInstance.observationTypes), TYPE_LIST_STRING);
            entity.setMultiObservationDataTypes(observationTypes);

            String observedArea = tuple.get(qInstance.observedArea.asText());
            if (observedArea != null) {
                try {
                    Polygon polygon = GeoHelper.parsePolygon(observedArea);
                    entity.setObservedArea(polygon);
                } catch (IllegalArgumentException e) {
                    // It's not a polygon, probably a point or a line.
                }
            }

            Timestamp pTimeStart = tuple.get(qInstance.phenomenonTimeStart);
            Timestamp pTimeEnd = tuple.get(qInstance.phenomenonTimeEnd);
            if (pTimeStart != null && pTimeEnd != null) {
                entity.setPhenomenonTime(intervalFromTimes(pTimeStart, pTimeEnd));
            }

            Timestamp rTimeStart = tuple.get(qInstance.resultTimeStart);
            Timestamp rTimeEnd = tuple.get(qInstance.resultTimeEnd);
            if (rTimeStart != null && rTimeEnd != null) {
                entity.setResultTime(intervalFromTimes(rTimeStart, rTimeEnd));
            }

            entity.setSensor(sensorFromId(tuple.get(qInstance.sensorId)));
            entity.setThing(thingFromId(tuple.get(qInstance.thingId)));

            List<UnitOfMeasurement> units = jsonToObject(tuple.get(qInstance.unitOfMeasurements), TYPE_LIST_UOM);
            entity.setUnitOfMeasurements(units);
            return entity;
        }

        @Override
        public NumberPath<Long> getPrimaryKey() {
            return qInstance.id;
        }

        @Override
        public EntityType getEntityType() {
            return EntityType.MultiDatastream;
        }

    }

    public static class ThingFactory implements PropertyHelper.entityFromTupleFactory<Thing> {

        public static final ThingFactory withDefaultAlias = new ThingFactory(
                new QThings(PathSqlBuilder.ALIAS_PREFIX + "1"));
        private final QThings qInstance;

        public ThingFactory(QThings qInstance) {
            this.qInstance = qInstance;
        }

        @Override
        public Thing create(Tuple tuple) {
            Thing entity = new Thing();
            entity.setName(tuple.get(qInstance.name));
            entity.setDescription(tuple.get(qInstance.description));
            Long id = tuple.get(qInstance.id);
            if (id != null) {
                entity.setId(new LongId(tuple.get(qInstance.id)));
            }

            String props = tuple.get(qInstance.properties);
            entity.setProperties(jsonToObject(props, Map.class));
            return entity;
        }

        @Override
        public NumberPath<Long> getPrimaryKey() {
            return qInstance.id;
        }

        @Override
        public EntityType getEntityType() {
            return EntityType.Thing;
        }

    }

    public static class FeatureOfInterestFactory
            implements PropertyHelper.entityFromTupleFactory<FeatureOfInterest> {

        public static final FeatureOfInterestFactory withDefaultAlias = new FeatureOfInterestFactory(
                new QFeatures(PathSqlBuilder.ALIAS_PREFIX + "1"));
        private final QFeatures qInstance;

        public FeatureOfInterestFactory(QFeatures qInstance) {
            this.qInstance = qInstance;
        }

        @Override
        public FeatureOfInterest create(Tuple tuple) {
            FeatureOfInterest entity = new FeatureOfInterest();
            Long id = tuple.get(qInstance.id);
            if (id != null) {
                entity.setId(new LongId(tuple.get(qInstance.id)));
            }

            entity.setName(tuple.get(qInstance.name));
            entity.setDescription(tuple.get(qInstance.description));
            String encodingType = tuple.get(qInstance.encodingType);
            String locationString = tuple.get(qInstance.feature);
            entity.setEncodingType(encodingType);
            entity.setFeature(locationFromEncoding(encodingType, locationString));
            return entity;
        }

        @Override
        public NumberPath<Long> getPrimaryKey() {
            return qInstance.id;
        }

        @Override
        public EntityType getEntityType() {
            return EntityType.FeatureOfInterest;
        }

    }

    public static class HistoricalLocationFactory
            implements PropertyHelper.entityFromTupleFactory<HistoricalLocation> {

        public static final HistoricalLocationFactory withDefaultAlias = new HistoricalLocationFactory(
                new QHistLocations(PathSqlBuilder.ALIAS_PREFIX + "1"));
        private final QHistLocations qInstance;

        public HistoricalLocationFactory(QHistLocations qInstance) {
            this.qInstance = qInstance;
        }

        @Override
        public HistoricalLocation create(Tuple tuple) {
            HistoricalLocation entity = new HistoricalLocation();
            Long id = tuple.get(qInstance.id);
            if (id != null) {
                entity.setId(new LongId(tuple.get(qInstance.id)));
            }

            entity.setThing(thingFromId(tuple.get(qInstance.thingId)));
            entity.setTime(instantFromTime(tuple.get(qInstance.time)));
            return entity;
        }

        @Override
        public NumberPath<Long> getPrimaryKey() {
            return qInstance.id;
        }

        @Override
        public EntityType getEntityType() {
            return EntityType.HistoricalLocation;
        }

    }

    public static class LocationFactory implements PropertyHelper.entityFromTupleFactory<Location> {

        public static final LocationFactory withDefaultAlias = new LocationFactory(
                new QLocations(PathSqlBuilder.ALIAS_PREFIX + "1"));
        private final QLocations qInstance;

        public LocationFactory(QLocations qInstance) {
            this.qInstance = qInstance;
        }

        @Override
        public Location create(Tuple tuple) {
            Location entity = new Location();
            Long id = tuple.get(qInstance.id);
            if (id != null) {
                entity.setId(new LongId(tuple.get(qInstance.id)));
            }

            entity.setName(tuple.get(qInstance.name));
            entity.setDescription(tuple.get(qInstance.description));
            String encodingType = tuple.get(qInstance.encodingType);
            String locationString = tuple.get(qInstance.location);
            entity.setEncodingType(encodingType);
            entity.setLocation(locationFromEncoding(encodingType, locationString));
            return entity;
        }

        @Override
        public NumberPath<Long> getPrimaryKey() {
            return qInstance.id;
        }

        @Override
        public EntityType getEntityType() {
            return EntityType.Location;
        }

    }

    public static class SensorFactory implements PropertyHelper.entityFromTupleFactory<Sensor> {

        public static final SensorFactory withDefaultAlias = new SensorFactory(
                new QSensors(PathSqlBuilder.ALIAS_PREFIX + "1"));
        private final QSensors qInstance;

        public SensorFactory(QSensors qInstance) {
            this.qInstance = qInstance;
        }

        @Override
        public Sensor create(Tuple tuple) {
            Sensor entity = new Sensor();
            entity.setName(tuple.get(qInstance.name));
            entity.setDescription(tuple.get(qInstance.description));
            entity.setEncodingType(tuple.get(qInstance.encodingType));
            Long id = tuple.get(qInstance.id);
            if (id != null) {
                entity.setId(new LongId(tuple.get(qInstance.id)));
            }

            entity.setMetadata(tuple.get(qInstance.metadata));
            return entity;
        }

        @Override
        public NumberPath<Long> getPrimaryKey() {
            return qInstance.id;
        }

        @Override
        public EntityType getEntityType() {
            return EntityType.Sensor;
        }

    }

    public static class ObservationFactory implements PropertyHelper.entityFromTupleFactory<Observation> {

        public static final ObservationFactory withDefaultAlias = new ObservationFactory(
                new QObservations(PathSqlBuilder.ALIAS_PREFIX + "1"));
        private final QObservations qInstance;

        public ObservationFactory(QObservations qInstance) {
            this.qInstance = qInstance;
        }

        @Override
        public Observation create(Tuple tuple) {
            Observation entity = new Observation();

            Long dsId = tuple.get(qInstance.datastreamId);
            if (dsId != null) {
                entity.setDatastream(datastreamFromId(dsId));
            }
            Long mDsId = tuple.get(qInstance.multiDatastreamId);
            if (mDsId != null) {
                entity.setMultiDatastream(multiDatastreamFromId(mDsId));
            }

            entity.setFeatureOfInterest(featureOfInterestFromId(tuple.get(qInstance.featureId)));
            Long id = tuple.get(qInstance.id);
            if (id != null) {
                entity.setId(new LongId(tuple.get(qInstance.id)));
            }

            String props = tuple.get(qInstance.parameters);
            entity.setParameters(jsonToObject(props, Map.class));

            Timestamp pTimeStart = tuple.get(qInstance.phenomenonTimeStart);
            Timestamp pTimeEnd = tuple.get(qInstance.phenomenonTimeEnd);
            entity.setPhenomenonTime(valueFromTimes(pTimeStart, pTimeEnd));

            Byte resultTypeOrd = tuple.get(qInstance.resultType);
            if (resultTypeOrd != null) {
                ResultType resultType = ResultType.fromSqlValue(resultTypeOrd);
                String stringRes = tuple.get(qInstance.resultString);
                switch (resultType) {
                case BOOLEAN:
                    entity.setResult(tuple.get(qInstance.resultBoolean));
                    break;

                case NUMBER:
                    try {
                        entity.setResult(new BigDecimal(stringRes));
                    } catch (NumberFormatException e) {
                        // It was not a Number? Use the double value.
                        entity.setResult(tuple.get(qInstance.resultNumber));
                    }
                    break;

                case OBJECT_ARRAY:
                    entity.setResult(jsonToTree(tuple.get(qInstance.resultJson)));
                    break;

                case STRING:
                    entity.setResult(stringRes);
                    break;
                }
            }

            String resultQuality = tuple.get(qInstance.resultQuality);
            entity.setResultQuality(jsonToObject(resultQuality, Object.class));
            entity.setResultTime(instantFromTime(tuple.get(qInstance.resultTime)));

            Timestamp vTimeStart = tuple.get(qInstance.validTimeStart);
            Timestamp vTimeEnd = tuple.get(qInstance.validTimeEnd);
            if (vTimeStart != null && vTimeEnd != null) {
                entity.setValidTime(intervalFromTimes(vTimeStart, vTimeEnd));
            }
            return entity;
        }

        @Override
        public NumberPath<Long> getPrimaryKey() {
            return qInstance.id;
        }

        @Override
        public EntityType getEntityType() {
            return EntityType.Observation;
        }

    }

    public static class ObservedPropertyFactory implements PropertyHelper.entityFromTupleFactory<ObservedProperty> {

        public static final ObservedPropertyFactory withDefaultAlias = new ObservedPropertyFactory(
                new QObsProperties(PathSqlBuilder.ALIAS_PREFIX + "1"));
        private final QObsProperties qInstance;

        public ObservedPropertyFactory(QObsProperties qInstance) {
            this.qInstance = qInstance;
        }

        @Override
        public ObservedProperty create(Tuple tuple) {
            ObservedProperty entity = new ObservedProperty();
            entity.setDefinition(tuple.get(qInstance.definition));
            entity.setDescription(tuple.get(qInstance.description));
            Long id = tuple.get(qInstance.id);
            if (id != null) {
                entity.setId(new LongId(tuple.get(qInstance.id)));
            }

            entity.setName(tuple.get(qInstance.name));
            return entity;
        }

        @Override
        public NumberPath<Long> getPrimaryKey() {
            return qInstance.id;
        }

        @Override
        public EntityType getEntityType() {
            return EntityType.ObservedProperty;
        }

    }

    static {
        FACTORY_PER_ENTITY.put(Datastream.class, DatastreamFactory.withDefaultAlias);
        FACTORY_PER_ENTITY.put(MultiDatastream.class, MultiDatastreamFactory.withDefaultAlias);
        FACTORY_PER_ENTITY.put(Thing.class, ThingFactory.withDefaultAlias);
        FACTORY_PER_ENTITY.put(FeatureOfInterest.class, FeatureOfInterestFactory.withDefaultAlias);
        FACTORY_PER_ENTITY.put(HistoricalLocation.class, HistoricalLocationFactory.withDefaultAlias);
        FACTORY_PER_ENTITY.put(Location.class, LocationFactory.withDefaultAlias);
        FACTORY_PER_ENTITY.put(Sensor.class, SensorFactory.withDefaultAlias);
        FACTORY_PER_ENTITY.put(Observation.class, ObservationFactory.withDefaultAlias);
        FACTORY_PER_ENTITY.put(ObservedProperty.class, ObservedPropertyFactory.withDefaultAlias);
    }

    /**
     * Get the factory for the given entity class, using the default alias
     * PathSqlBuilder.ALIAS_PREFIX + "1".
     *
     * @param <T> The type of entity to get the factory for.
     * @param clazz The class of the entity to get the factory for.
     * @return the factory for the given entity class.
     */
    public static <T extends Entity> entityFromTupleFactory<T> getFactoryFor(Class<T> clazz) {
        entityFromTupleFactory<? extends Entity> factory = FACTORY_PER_ENTITY.get(clazz);
        if (factory == null) {
            throw new AssertionError("No factory found for " + clazz.getName());
        }
        return (entityFromTupleFactory<T>) factory;
    }

    private static TimeInterval intervalFromTimes(Timestamp timeStart, Timestamp timeEnd) {
        if (timeStart == null) {
            timeStart = Timestamp.valueOf(LocalDateTime.MAX);
        }
        if (timeEnd == null) {
            timeEnd = Timestamp.valueOf(LocalDateTime.MIN);
        }
        if (timeEnd.before(timeStart)) {
            return null;
        } else {
            return TimeInterval.create(timeStart.getTime(), timeEnd.getTime());
        }
    }

    private static TimeInstant instantFromTime(Timestamp time) {
        if (time == null) {
            return new TimeInstant(null);
        }
        return TimeInstant.create(time.getTime());
    }

    private static TimeValue valueFromTimes(Timestamp timeStart, Timestamp timeEnd) {
        if (timeEnd == null || timeEnd.equals(timeStart)) {
            return instantFromTime(timeStart);
        }
        return intervalFromTimes(timeStart, timeEnd);
    }

    private static Datastream datastreamFromId(Long id) {
        if (id == null) {
            return null;
        }
        Datastream ds = new Datastream();
        ds.setId(new LongId(id));
        ds.setExportObject(false);
        return ds;
    }

    private static MultiDatastream multiDatastreamFromId(Long id) {
        if (id == null) {
            return null;
        }
        MultiDatastream ds = new MultiDatastream();
        ds.setId(new LongId(id));
        ds.setExportObject(false);
        return ds;
    }

    private static FeatureOfInterest featureOfInterestFromId(Long id) {
        if (id == null) {
            return null;
        }
        FeatureOfInterest foi = new FeatureOfInterest();
        foi.setId(new LongId(id));
        foi.setExportObject(false);
        return foi;
    }

    private static ObservedProperty observedProperyFromId(Long id) {
        if (id == null) {
            return null;
        }
        ObservedProperty op = new ObservedProperty();
        op.setId(new LongId(id));
        op.setExportObject(false);
        return op;
    }

    private static Sensor sensorFromId(Long id) {
        if (id == null) {
            return null;
        }
        Sensor sensor = new Sensor();
        sensor.setId(new LongId(id));
        sensor.setExportObject(false);
        return sensor;
    }

    private static Thing thingFromId(Long id) {
        if (id == null) {
            return null;
        }
        Thing thing = new Thing();
        thing.setId(new LongId(id));
        thing.setExportObject(false);
        return thing;
    }

    public static Object locationFromEncoding(String encodingType, String locationString) {
        if (locationString == null || locationString.isEmpty()) {
            return null;
        }
        if ("application/vnd.geo+json".equalsIgnoreCase(encodingType)) {
            try {
                Object geoJson = new GeoJsonDeserializier().deserialize(locationString);
                return geoJson;
            } catch (IOException ex) {
                LOGGER.error("Failed to deserialise geoJson.");

            }
        } else {
            try {
                Map map = jsonToObject(locationString, Map.class);
                return map;
            } catch (Exception e) {
                LOGGER.trace("Not a map.");
            }
            return locationString;
        }
        return null;
    }

    public static JsonNode jsonToTree(String json) {
        if (json == null) {
            return null;
        }

        try {
            return new ObjectMapper().readTree(json);
        } catch (IOException ex) {
            throw new IllegalStateException("Failed to parse stored json.", ex);
        }
    }

    public static <T> T jsonToObject(String json, Class<T> clazz) {
        if (json == null) {
            return null;
        }
        try {
            return new ObjectMapper().readValue(json, clazz);
        } catch (IOException ex) {
            throw new IllegalStateException("Failed to parse stored json.", ex);
        }
    }

    public static <T> T jsonToObject(String json, TypeReference<T> typeReference) {
        if (json == null) {
            return null;
        }
        try {
            return new ObjectMapper().readValue(json, typeReference);
        } catch (IOException ex) {
            throw new IllegalStateException("Failed to parse stored json.", ex);
        }
    }

}