de.ks.flatadocdb.defaults.DefaultEntityPersister.java Source code

Java tutorial

Introduction

Here is the source code for de.ks.flatadocdb.defaults.DefaultEntityPersister.java

Source

/*
 * Copyright [2015] [Christian Loehnert]
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package de.ks.flatadocdb.defaults;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.*;
import de.ks.flatadocdb.Repository;
import de.ks.flatadocdb.defaults.json.SerializationModule;
import de.ks.flatadocdb.ifc.EntityPersister;
import de.ks.flatadocdb.metamodel.EntityDescriptor;
import de.ks.flatadocdb.metamodel.MetaModel;
import de.ks.flatadocdb.metamodel.relation.Relation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;

/**
 * Default JSON entity persister.
 * Used to store and load json files.
 * Also handles reading/saving relations correctly.
 */
public class DefaultEntityPersister implements EntityPersister {
    private static final Logger log = LoggerFactory.getLogger(DefaultEntityPersister.class);
    final ObjectMapper mapper = new ObjectMapper();

    public DefaultEntityPersister() {
        mapper.findAndRegisterModules();
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
        mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
        mapper.enableDefaultTyping();
        mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_OBJECT);
        mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    @Override
    public void initialize(MetaModel metaModel) {
        Module module = new SerializationModule(metaModel);
        mapper.registerModule(module);
    }

    @Override
    public Object load(Repository repository, EntityDescriptor descriptor, Path path,
            Map<Relation, Collection<String>> relationIds) {
        try {
            JsonNode jsonNode = mapper.readTree(path.toFile());
            descriptor.getAllRelations().forEach(rel -> {
                String name = rel.getRelationField().getName();
                JsonNode jsonValue = jsonNode.findValue(name);
                if (jsonValue.elements().hasNext()) {
                    jsonValue = jsonValue.elements().next();
                }

                ArrayList<String> ids = new ArrayList<>();

                relationIds.put(rel, ids);

                if (jsonValue.isContainerNode()) {
                    jsonValue.elements().forEachRemaining(id -> ids.add(id.asText()));
                } else if (!jsonValue.isNull()) {
                    ids.add(jsonValue.asText());
                }
                log.debug("Found {} relation id's in {}: {}", ids.size(), name, ids);
            });
            return mapper.readValue(path.toFile(), descriptor.getEntityClass());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public byte[] createFileContents(Repository repository, EntityDescriptor descriptor, Object object) {
        try {
            //      return mapper.writeValueAsBytes(object); change with below to avoid pretty printing, nah ;)
            return mapper.writerWithDefaultPrettyPrinter().writeValueAsBytes(object);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public boolean canParse(Path path, EntityDescriptor descriptor) {
        if (path.toFile().exists()) {
            try (FileInputStream stream = new FileInputStream(path.toFile())) {
                try (LineNumberReader reader = new LineNumberReader(new InputStreamReader(stream))) {
                    String line1 = reader.readLine();
                    String line2 = reader.readLine();
                    line1 = line1 == null ? "" : line1.trim();
                    line2 = line2 == null ? "" : line2.trim();
                    boolean valid = checkLine(line1, line2, descriptor.getEntityClass());
                    if (valid) {
                        log.debug("Found valid file {} to parse as {}", path,
                                descriptor.getEntityClass().getSimpleName());
                    }
                    return valid;
                }
            } catch (IOException e) {
                log.debug("Unable to parse {} as {}", path, descriptor.getEntityClass(), e);
                return false;
            }
        }
        return false;
    }

    private boolean checkLine(String line1, String line2, Class<?> clazz) {
        boolean prettyPrintedLine = line2.startsWith("\"" + clazz.getName() + "\"");
        boolean inlineDeclaration = line1.startsWith("{\"" + clazz.getName() + "\":");
        return prettyPrintedLine || inlineDeclaration;
    }
}