/* See LICENSE for licensing and NOTICE for copyright. */ package org.ldaptive.io; import java.io.IOException; import java.io.Reader; import java.lang.reflect.Type; import java.util.Map; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; import org.ldaptive.LdapAttribute; import org.ldaptive.LdapEntry; import org.ldaptive.SearchResult; import org.ldaptive.SortBehavior; /** * Reads JSON from a {@link Reader} and returns a {@link SearchResult}. * * @author Middleware Services */ public class JsonReader implements SearchResultReader { /** Reader to read from. */ private final Reader jsonReader; /** To convert JSON to a search result. */ private final Gson gson; /** * Creates a new json reader. * * @param reader to read JSON from */ public JsonReader(final Reader reader) { this(reader, SortBehavior.getDefaultSortBehavior()); } /** * Creates a new json reader. * * @param reader to read JSON from * @param sb sort behavior of the search result */ public JsonReader(final Reader reader, final SortBehavior sb) { jsonReader = reader; if (sb == null) { throw new IllegalArgumentException("Sort behavior cannot be null"); } final GsonBuilder builder = new GsonBuilder(); builder.registerTypeAdapter(SearchResult.class, new SearchResultDeserializer(sb)); gson = builder.disableHtmlEscaping().create(); } /** * Reads JSON data from the reader and returns a search result. * * @return search result derived from the JSON * * @throws IOException if an error occurs using the reader */ @Override public SearchResult read() throws IOException { try { return gson.fromJson(jsonReader, SearchResult.class); } catch (JsonParseException e) { throw new IOException(e); } } /** * Deserializes a {@link SearchResult} by iterating over the json elements. */ private static class SearchResultDeserializer implements JsonDeserializer<SearchResult> { /** Sort behavior. */ private final SortBehavior sortBehavior; /** * Creates a new search result deserializer. * * @param sb sort behavior of the search result */ SearchResultDeserializer(final SortBehavior sb) { sortBehavior = sb; } @Override public SearchResult deserialize(final JsonElement json, final Type type, final JsonDeserializationContext context) throws JsonParseException { final SearchResult result = new SearchResult(sortBehavior); final JsonArray jsonResult = json.getAsJsonArray(); for (JsonElement jsonEntry : jsonResult) { final LdapEntry entry = new LdapEntry(sortBehavior); for (Map.Entry<String, JsonElement> jsonAttr : jsonEntry.getAsJsonObject().entrySet()) { if ("dn".equals(jsonAttr.getKey())) { entry.setDn(jsonAttr.getValue().getAsString()); } else { final LdapAttribute attr = new LdapAttribute(sortBehavior); attr.setName(jsonAttr.getKey()); jsonAttr.getValue().getAsJsonArray().forEach(i -> attr.addStringValue(i.getAsString())); entry.addAttribute(attr); } } result.addEntry(entry); } return result; } } }