package org.fenixedu.bennu.core.rest; import java.util.List; import java.util.Map.Entry; import org.fenixedu.bennu.core.domain.exceptions.BennuCoreDomainException; import org.fenixedu.bennu.core.json.JsonBuilder; import org.fenixedu.bennu.core.json.JsonCreator; import org.fenixedu.bennu.core.json.JsonUpdater; import org.fenixedu.bennu.core.json.JsonViewer; import org.fenixedu.bennu.core.util.CoreConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import pt.ist.fenixframework.Atomic; import pt.ist.fenixframework.Atomic.TxMode; import com.google.common.base.Strings; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.google.gson.JsonParser; public class JsonAwareResource { private static final Logger LOG = LoggerFactory.getLogger("RestAdapters"); private static final JsonBuilder BUILDER; private static final JsonParser PARSER; private static final Gson GSON; static { PARSER = new JsonParser(); BUILDER = new JsonBuilder(); if (CoreConfiguration.getConfiguration().developmentMode()) { GSON = new GsonBuilder().setPrettyPrinting().create(); } else { GSON = new GsonBuilder().create(); } } public static final JsonBuilder getBuilder() { return BUILDER; } public static final void setDefault(Class<?> objectClass, Class<?> registeeClass) { BUILDER.setDefault(objectClass, registeeClass); } public final JsonElement view(Object object) { return view(object, (Class<? extends JsonViewer<?>>) null); } public final JsonElement view(Object object, Class<? extends JsonViewer<?>> viewerClass) { if (object == null) { return view(object, (Class<?>) null, viewerClass); } return view(object, object.getClass(), viewerClass); } public final JsonElement view(Object object, Class<?> objectClass, Class<? extends JsonViewer<?>> viewerClass) { return BUILDER.view(object, objectClass, viewerClass); } public final JsonElement view(Object object, String collectionKey) { return view(object, collectionKey, null); } public final JsonElement view(Object object, String collectionKey, Class<? extends JsonViewer<?>> viewerClass) { if (object == null) { return view(object, (Class<?>) null, collectionKey, viewerClass); } return view(object, object.getClass(), collectionKey, viewerClass); } public final JsonElement view(Object object, Class<?> objectClass, String collectionKey, Class<? extends JsonViewer<?>> viewerClass) { JsonObject jsonObject = new JsonObject(); jsonObject.add(collectionKey, BUILDER.view(object, objectClass, viewerClass)); return jsonObject; } public final JsonElement viewPaginated(List<?> object, String collectionKey, int skip, int pageSize) { return viewPaginated(object, collectionKey, null, skip, pageSize); } public final JsonElement viewPaginated(List<?> object, String collectionKey, Class<? extends JsonViewer<?>> viewerClass, int skip, int pageSize) { if (object == null) { return viewPaginated(null, (Class<?>) null, collectionKey, viewerClass, skip, pageSize); } return viewPaginated(object, object.getClass(), collectionKey, viewerClass, skip, pageSize); } public final JsonElement viewPaginated(List<?> object, Class<?> objectClass, String collectionKey, Class<? extends JsonViewer<?>> viewerClass, int skip, int pageSize) { JsonObject jsonObject = new JsonObject(); if (object == null) { jsonObject.add(collectionKey, new JsonArray()); jsonObject.addProperty("total", 0); } else { jsonObject.add(collectionKey, BUILDER.view( object.subList(Math.min(object.size(), skip), Math.min(object.size(), skip + pageSize)), objectClass, viewerClass)); jsonObject.addProperty("total", object.size()); } return jsonObject; } public <T> T create(JsonElement jsonData, Class<T> clazz) { return create(jsonData, clazz, null); } @SuppressWarnings("unchecked") public <T> T create(JsonElement jsonData, Class<T> clazz, Class<? extends JsonCreator<? extends T>> jsonCreatorClass) { LOG.trace("Create instance of {} with data {}", clazz.getSimpleName(), jsonData); return (T) innerCreate(jsonData, clazz, jsonCreatorClass); } @Atomic(mode = TxMode.WRITE) private Object innerCreate(JsonElement jsonData, Class<?> clazz, Class<? extends JsonCreator<?>> jsonCreatorClass) { return BUILDER.create(jsonData, clazz, jsonCreatorClass); } public <T> T update(JsonElement jsonData, T object) { return update(jsonData, object, null); } @SuppressWarnings("unchecked") public <T> T update(JsonElement jsonData, T object, Class<? extends JsonUpdater<? extends T>> jsonUpdaterClass) { LOG.trace("Update instance {} with data {}", object.toString(), jsonData); return (T) innerUpdate(jsonData, object, jsonUpdaterClass); } @Atomic(mode = TxMode.WRITE) private Object innerUpdate(JsonElement jsonData, Object object, Class<? extends JsonUpdater<?>> jsonUpdaterClass) { return BUILDER.update(jsonData, object, jsonUpdaterClass); } protected JsonElement parse(String jsonString) { try { if (Strings.isNullOrEmpty(jsonString)) { return new JsonObject(); } return PARSER.parse(jsonString); } catch (JsonParseException | IllegalStateException e) { throw BennuCoreDomainException.parseError(); } } public static String toJson(JsonElement el) { return GSON.toJson(el); } /** * merges the source within target * * @param target json where to merge the source * @param source the json source to merge */ public void merge(JsonObject target, JsonObject source) { for (final Entry<String, JsonElement> entry : source.entrySet()) { target.add(entry.getKey(), entry.getValue()); } } }