org.javersion.object.types.BasicObjectType.java Source code

Java tutorial

Introduction

Here is the source code for org.javersion.object.types.BasicObjectType.java

Source

/*
 * Copyright 2013 Samppa Saarela
 *
 * 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 org.javersion.object.types;

import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;

import javax.annotation.Nullable;

import org.javersion.core.Persistent;
import org.javersion.object.ReadContext;
import org.javersion.object.WriteContext;
import org.javersion.path.NodeId;
import org.javersion.path.PropertyPath;
import org.javersion.path.PropertyTree;
import org.javersion.reflect.FieldDescriptor;
import org.javersion.reflect.Property;
import org.javersion.reflect.TypeDescriptor;
import org.javersion.util.Check;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;

public class BasicObjectType implements ObjectType {

    public static BasicObjectType of(TypeDescriptor type) {
        return of(type, type.getSimpleName(), null);
    }

    public static BasicObjectType of(TypeDescriptor type, @Nullable Set<String> fieldNames) {
        return of(type, type.getSimpleName(), fieldNames);
    }

    public static BasicObjectType of(TypeDescriptor type, String alias) {
        return of(type, alias, null);
    }

    public static BasicObjectType of(TypeDescriptor type, String alias, @Nullable Set<String> fieldNames) {
        Map<String, FieldDescriptor> fields = type.getFields();
        if (fields != null) {
            fields = Maps.filterEntries(fields, entry -> fieldNames.contains(entry.getKey()));
        }
        return of(type, alias, new ObjectCreator(type), null, fields);
    }

    public static BasicObjectType of(TypeDescriptor type, String alias, ObjectCreator constructor,
            ObjectIdentifier identifier, Map<String, ? extends Property> properties) {
        if (identifier != null) {
            return new Identifiable(type, alias, constructor, identifier, properties);
        } else {
            return new BasicObjectType(type, alias, constructor, null, properties);
        }
    }

    private final Map<String, Property> properties;

    private final ObjectCreator constructor;

    private final ObjectIdentifier identifier;

    private final String alias;

    private final TypeDescriptor type;

    private BasicObjectType(TypeDescriptor type, String alias, ObjectCreator constructor,
            ObjectIdentifier identifier, Map<String, ? extends Property> properties) {
        this.type = Check.notNull(type, "type");
        this.alias = Check.notNullOrEmpty(alias, "alias");
        this.constructor = constructor;
        this.identifier = identifier;
        this.properties = ImmutableMap.copyOf(properties);
    }

    @Override
    public Object instantiate(PropertyTree propertyTree, Object valueObject, ReadContext context) throws Exception {
        Object[] params = constructor.newParametersArray();
        int i = 0;
        for (String param : constructor.getParameters()) {
            PropertyTree child = propertyTree.get(NodeId.property(param));
            Object value = child != null ? context.getObject(child) : null;
            params[i++] = value;
        }
        if (constructor.hasParameters()) {
            // Ensure that constructor parameters are bound
            context.bindAll();
        }
        Object object = constructor.newInstance(params);
        if (identifier != null && !constructor.hasParameter(identifier.name) && identifier.property.isWritable()) {
            PropertyTree child = propertyTree.get(NodeId.property(identifier.name));
            if (child != null) {
                Object value = context.getObject(child);
                if (value != null) {
                    identifier.property.set(object, value);
                }
            }
        }
        return object;
    }

    @Override
    public void bind(PropertyTree propertyTree, Object object, ReadContext context) throws Exception {
        for (PropertyTree child : propertyTree.getChildren()) {
            NodeId nodeId = child.getNodeId();
            if (nodeId.isKey() && !constructor.hasParameter(nodeId.getKey())) {
                Property property = properties.get(nodeId.getKey());
                if (property != null && property.isWritable()) {
                    Object value = context.getObject(child);
                    property.set(object, value);
                }
            }
        }
    }

    public ObjectIdentifier getIdentifier() {
        return identifier;
    }

    public Map<String, Property> getProperties() {
        return properties;
    }

    @Override
    public void serialize(PropertyPath path, Object object, WriteContext context) {
        context.put(path, Persistent.object(alias));
        BiConsumer<String, Property> propertySerializer = (name, property) -> {
            PropertyPath subPath = path.property(name);
            Object value = property.get(object);
            context.serialize(subPath, value);
        };
        properties.forEach(propertySerializer);

        if (identifier != null && identifier.property.isWritable()) {
            propertySerializer.accept(identifier.name, identifier.property);
        }
    }

    public String getAlias() {
        return alias;
    }

    public TypeDescriptor getType() {
        return type;
    }

    public NodeId toNodeId(Object object, WriteContext writeContext) {
        if (identifier == null) {
            throw new UnsupportedOperationException("toNodeId is not supported for composite ids");
        }
        Object id = identifier.property.get(object);
        return identifier.idType.toNodeId(id, writeContext);
    }

    public String toString() {
        return "BasicObjectType of " + type;
    }

    private static class Identifiable extends BasicObjectType implements IdentifiableType {
        private Identifiable(TypeDescriptor type, String alias, ObjectCreator constructor,
                ObjectIdentifier identifier, Map<String, ? extends Property> properties) {
            super(type, alias, constructor, identifier, properties);
        }
    }

}