/*
* Copyright 2013 Google Inc.
*
* 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 com.google.gwt.core.ext.soyc.coderef;
import com.google.gwt.core.ext.soyc.coderef.EntityDescriptor.Fragment;
import com.google.gwt.thirdparty.guava.common.collect.Maps;
import com.google.gwt.thirdparty.json.JSONArray;
import com.google.gwt.thirdparty.json.JSONException;
import com.google.gwt.thirdparty.json.JSONObject;
import java.util.Map;
/**
* Serialize/Deserialize EntityDescriptor instances to/from json.
*
*/
public class EntityDescriptorJsonTranslator {
private static class Deserializer {
private final Map<Integer, MethodDescriptor> mapMethods = Maps.newHashMap();
private final Map<MethodDescriptor, JSONArray> mapDependants = Maps.newIdentityHashMap();
private PackageDescriptor readJson(JSONObject jsonObject) throws JSONException {
String packageName = jsonObject.getString(ENTITY_NAME);
PackageDescriptor packageDescriptor = readJsonPackage(jsonObject, packageName,
packageName.equals(PackageDescriptor.DEFAULT_PKG) ? "" : packageName);
setMethodDependencies();
return packageDescriptor;
}
private void setMethodDependencies() throws JSONException {
for (MethodDescriptor method : mapDependants.keySet()) {
JSONArray dependants = mapDependants.get(method);
for (int i = 0; i < dependants.length(); i++) {
method.addDependant(mapMethods.get(dependants.getInt(i)));
}
}
}
private PackageDescriptor readJsonPackage(JSONObject jsonObject, String name,
String longName) throws JSONException {
PackageDescriptor descriptor = new PackageDescriptor(name, longName);
JSONArray clss = jsonObject.getJSONArray(CLASSES);
for (int i = 0; i < clss.length(); i++) {
descriptor.addClass(readJsonClass(clss.getJSONObject(i), longName));
}
JSONArray packages = jsonObject.getJSONArray(PACKAGES);
for (int i = 0; i < packages.length(); i++) {
JSONObject subPackage = packages.getJSONObject(i);
String packageName = subPackage.getString(ENTITY_NAME);
descriptor.addPackage(readJsonPackage(subPackage, packageName,
longName + (longName.isEmpty() ? "" : ".") + packageName));
}
return descriptor;
}
private ClassDescriptor readJsonClass(JSONObject jsonObject, String packageName)
throws JSONException {
ClassDescriptor descriptor = new ClassDescriptor(jsonObject.getString("name"), packageName);
updateEntity(descriptor, jsonObject);
JSONArray fields = jsonObject.getJSONArray(FIELDS);
for (int i = 0; i < fields.length(); i++) {
descriptor.addField(readJsonField(fields.getJSONObject(i), descriptor));
}
JSONArray methods = jsonObject.getJSONArray(METHODS);
for (int i = 0; i < methods.length(); i++) {
descriptor.addMethod(readJsonMethod(methods.getJSONObject(i), descriptor));
}
return descriptor;
}
private MethodDescriptor readJsonMethod(JSONObject jsonObject, ClassDescriptor classDescriptor)
throws JSONException {
MethodDescriptor method = new MethodDescriptor(classDescriptor,
jsonObject.getString(ENTITY_NAME));
updateEntity(method, jsonObject);
method.setUniqueId(jsonObject.getInt(METHOD_ID));
mapMethods.put(method.getUniqueId(), method);
mapDependants.put(method, jsonObject.getJSONArray(METHOD_DEPENDENTS));
return method;
}
private FieldDescriptor readJsonField(JSONObject jsonObject, ClassDescriptor classDescriptor)
throws JSONException {
String[] fullName = jsonObject.getString(ENTITY_NAME).split(":");
FieldDescriptor fieldDescriptor = new FieldDescriptor(classDescriptor, fullName[0], fullName[1]);
updateEntity(fieldDescriptor, jsonObject);
return fieldDescriptor;
}
private void updateEntity(EntityDescriptor entity, JSONObject jsonObject) throws JSONException {
JSONArray jsNames = jsonObject.getJSONArray(ENTITY_JS);
for (int i = 0; i < jsNames.length(); i++) {
entity.addObfuscatedName(jsNames.getString(i));
}
JSONArray frags = jsonObject.getJSONArray(EntityRecorder.FRAGMENTS);
for (int i = 0; i < frags.length(); i++) {
JSONObject frag = frags.getJSONObject(i);
entity.addFragment(
new Fragment(frag.getInt(EntityRecorder.FRAGMENT_ID),
frag.getInt(EntityRecorder.FRAGMENT_SIZE)));
}
}
}
public static final String ENTITY_JS = "js";
public static final String ENTITY_NAME = "name";
public static final String FIELDS = "fields";
public static final String METHOD_ID = "id";
public static final String METHOD_DEPENDENTS = "dependents";
public static final String METHODS = "methods";
public static final String CLASSES = "classes";
public static final String PACKAGES = "packages";
private static JSONObject writeJsonFromEntity(EntityDescriptor entity) throws JSONException {
JSONObject json = new JSONObject();
JSONArray fragments = new JSONArray();
for (EntityDescriptor.Fragment frg : entity.getFragments()) {
JSONObject frag = new JSONObject();
frag.put(EntityRecorder.FRAGMENT_ID, frg.getId());
frag.put(EntityRecorder.FRAGMENT_SIZE, frg.getSize());
fragments.put(frag);
}
json.put(EntityRecorder.FRAGMENTS, fragments);
json.put(ENTITY_JS, new JSONArray(entity.getObfuscatedNames()));
return json;
}
private static JSONObject writeJsonFromMember(MemberDescriptor entity) throws JSONException {
JSONObject json = writeJsonFromEntity(entity);
json.put(ENTITY_NAME, entity.getJsniSignature());
return json;
}
public static JSONObject writeJson(PackageDescriptor pkg) throws JSONException {
JSONObject json = new JSONObject();
json.put(ENTITY_NAME, pkg.getName());
// classes
JSONArray classes = new JSONArray();
for (ClassDescriptor classDescriptor : pkg.getClasses()) {
JSONObject jsonClass = writeJsonFromEntity(classDescriptor);
jsonClass.put(ENTITY_NAME, classDescriptor.getName());
// fields
JSONArray fields = new JSONArray();
for (FieldDescriptor fieldDescriptor : classDescriptor.getFields()) {
fields.put(writeJsonFromMember(fieldDescriptor));
}
jsonClass.put(FIELDS, fields);
// methods
JSONArray methods = new JSONArray();
for (MethodDescriptor methodDescriptor : classDescriptor.getMethods()) {
JSONObject jsonMethod = writeJsonFromMember(methodDescriptor);
jsonMethod.put(METHOD_ID, methodDescriptor.getUniqueId());
jsonMethod.put(METHOD_DEPENDENTS, new JSONArray(methodDescriptor.getDependentPointers()));
methods.put(jsonMethod);
}
jsonClass.put(METHODS, methods);
classes.put(jsonClass);
}
json.put(CLASSES, classes);
// packages
JSONArray packages = new JSONArray();
for (PackageDescriptor packageDescriptor : pkg.getPackages()) {
packages.put(writeJson(packageDescriptor));
}
json.put(PACKAGES, packages);
return json;
}
public static PackageDescriptor readJson(JSONObject jsonObject) throws JSONException {
return new Deserializer().readJson(jsonObject);
}
private EntityDescriptorJsonTranslator() { }
}