org.qi4j.runtime.types.SerializableType.java Source code

Java tutorial

Introduction

Here is the source code for org.qi4j.runtime.types.SerializableType.java

Source

/*
 * Copyright (c) 2009, Rickard berg. All Rights Reserved.
 *
 * 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.qi4j.runtime.types;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Proxy;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONWriter;
import org.qi4j.api.common.TypeName;
import org.qi4j.api.entity.EntityComposite;
import org.qi4j.api.entity.EntityReference;
import org.qi4j.api.structure.Module;
import org.qi4j.api.unitofwork.UnitOfWork;
import org.qi4j.api.value.ValueComposite;
import org.qi4j.spi.composite.CompositeInstance;
import org.qi4j.spi.property.ValueType;
import org.qi4j.spi.structure.ModuleSPI;
import org.qi4j.spi.util.Base64Encoder;
import org.qi4j.spi.value.ValueDescriptor;

/**
 * Serializable type. If the serialized object is an ValueComposite,
 * then use JSON format for VC's. If the serialized object is an
 * EntityReference, then use JSON format for EntityReferences.
 */
public final class SerializableType extends AbstractStringType {
    public SerializableType(TypeName type) {
        super(type);
    }

    public void toJSON(Object value, JSONWriter json) throws JSONException {
        json.value(toJSON(value));
    }

    public Object toJSON(Object value) throws JSONException {
        // Check if we are serializing an Entity
        if (value instanceof EntityComposite) {
            // Store reference instead
            value = EntityReference.getEntityReference(value);
        } else if (value instanceof ValueComposite) {
            // Serialize ValueComposite JSON instead
            CompositeInstance instance = (CompositeInstance) Proxy.getInvocationHandler(value);
            ValueDescriptor descriptor = (ValueDescriptor) instance.descriptor();
            ValueType valueType = descriptor.valueType();
            try {
                JSONObject object = (JSONObject) valueType.toJSON(value);
                object.put("_type", descriptor.type().getName());
                return object;
            } catch (JSONException e) {
                throw new IllegalStateException("Could not JSON serialize value", e);
            }
        }

        // Serialize value
        try {
            ByteArrayOutputStream bout = new ByteArrayOutputStream();
            ObjectOutputStream out = new ObjectOutputStream(bout);
            out.writeUnshared(value);
            out.close();
            byte[] bytes = Base64Encoder.encode(bout.toByteArray(), true);
            String stringValue = new String(bytes, "UTF-8");
            return stringValue;
        } catch (IOException e) {
            throw new IllegalArgumentException("Could not serialize value", e);
        }
    }

    public Object fromJSON(Object json, Module module) throws JSONException {
        try {
            if (json instanceof JSONObject) {
                // ValueComposite deserialization
                JSONObject jsonObject = (JSONObject) json;
                String type = jsonObject.getString("_type");

                ValueDescriptor valueDescriptor = ((ModuleSPI) module).valueDescriptor(type);
                return valueDescriptor.valueType().fromJSON(json, module);
            } else {
                String serializedString = (String) json;
                byte[] bytes = serializedString.getBytes("UTF-8");
                bytes = Base64Encoder.decode(bytes);
                ByteArrayInputStream bin = new ByteArrayInputStream(bytes);
                ObjectInputStream oin = new ObjectInputStream(bin);
                Object result = oin.readObject();
                oin.close();

                if (result instanceof EntityReference) {
                    EntityReference ref = (EntityReference) result;
                    if (!type.isClass(EntityReference.class)) {
                        Class mixinType = module.classLoader().loadClass(type.name());
                        UnitOfWork unitOfWork = module.unitOfWorkFactory().currentUnitOfWork();
                        if (unitOfWork != null) {
                            result = unitOfWork.get(mixinType, ref.identity());
                        }
                    }
                }

                return result;
            }
        } catch (IOException e) {
            throw new IllegalStateException("Could not deserialize value", e);
        } catch (ClassNotFoundException e) {
            throw new IllegalStateException("Could not find class for serialized value", e);
        }
    }

    @Override
    public String toQueryParameter(Object value) {
        String json = super.toQueryParameter(value);
        return json.substring(1, json.length() - 1);
    }

    @Override
    public Object fromQueryParameter(String parameter, Module module) throws JSONException {
        String json = "\"" + parameter + "\"";

        return fromJSON(json, module);
    }
}