All Downloads are FREE. Search and download functionalities are using the official Maven repository.

no.arktekk.siren.JsonParser Maven / Gradle / Ivy

package no.arktekk.siren;


import io.vavr.collection.List;
import io.vavr.control.Option;
import net.hamnaberg.json.Json;
import no.arktekk.siren.SubEntity.EmbeddedLink;
import no.arktekk.siren.SubEntity.EmbeddedRepresentation;

import java.net.URI;
import java.util.function.Function;

public interface JsonParser {

    Entity fromJson(T json);

    enum ImmutableJsonParser implements JsonParser {
        INSTANCE;

        public Entity fromJson(Json.JObject json) {
            return parseEntity(json);
        }

        private Entity parseEntity(Json.JObject object) {
            Option classes = object.getAsArray("class").map(l -> new Classes(l.getListAsStrings()));
            Option properties = object.getAsObject("properties");
            Option entities = object.getAsArray("entities").map(es -> new Entities(mapObjectList(es, this::parseSubEntity)));
            Option actions = object.getAsArray("actions").map(as -> new Actions(mapObjectList(as, this::parseAction)));
            Option links = object.getAsArray("links").map(ls -> new Links(mapObjectList(ls, this::parseLink)));
            return new Entity(classes, properties, entities, actions, links, parseTitle(object));
        }


        private Option parseTitle(Json.JObject object) {
            return object.getAsString("title");
        }

        private Link parseLink(Json.JObject obj) {
            URI href = getHref(obj, "Link");
            Rel rels = new Rel(obj.getAsArrayOrEmpty("rel").getListAsStrings());
            if (rels.isEmpty()) {
                throw new SirenParseException(String.format("Empty 'rel' in Link '%s'", obj));
            }
            Option type = obj.getAsString("type").flatMap(MIMEType::parse);
            Option classes = obj.getAsArray("class").map(cs -> new Classes(cs.getListAsStrings()));
            return new Link(rels, href, classes, type, parseTitle(obj));
        }

        private Action parseAction(Json.JObject action) {
            Option name = action.getAsString("name");
            if (!name.isDefined()) {
                throw new SirenParseException(String.format("Missing required 'name' field in Action '%s", action));
            }
            URI href = getHref(action, "Action");
            Option method = action.getAsString("method").map(Method::valueOf);
            Option type = action.getAsString("type").flatMap(MIMEType::parse);
            Option fields = action.getAsArray("fields").map(fs -> new Fields(mapObjectList(fs, this::parseField)));
            Option classes = action.getAsArray("class").map(cs -> new Classes(cs.getListAsStrings()));
            return new Action(name.get(), href, classes, parseTitle(action), method, type, fields);
        }

        private SubEntity parseSubEntity(Json.JObject entity) {
            if (entity.containsKey("href"))
                return parseEmbeddedLink(entity);
            else
                return parseEmbeddedRepresentation(entity);
        }

        private EmbeddedLink parseEmbeddedLink(Json.JObject embeddedLink) {
            Link link = parseLink(embeddedLink);
            return link.toEmbedded();
        }

        private EmbeddedRepresentation parseEmbeddedRepresentation(Json.JObject embeddedRepresentation) {
            Entity entity = parseEntity(embeddedRepresentation);
            Rel rel = new Rel(embeddedRepresentation.getAsArrayOrEmpty("rel").getListAsStrings());
            return new EmbeddedRepresentation(rel, entity);
        }

        private Field parseField(Json.JObject field) {
            String name = field.getAsString("name").getOrElseThrow(() -> new SirenParseException(String.format("Missing required 'name' field in Field '%s", field)));

            Option classes = field.getAsArray("class").map(cs -> new Classes(cs.getListAsStrings()));
            Option value = field.get("value");
            Option title = parseTitle(field);

            Option maybeNested = field.getAsArray("fields").map(fs -> new Fields(mapObjectList(fs, this::parseField))).map(schema -> new Field.NestedField(name, schema, classes, value, title));
            return maybeNested.getOrElse(() -> {
                Field.Type type = Field.Type.fromString(field.getAsString("type").getOrElse("text"));
                return new Field.SimpleField(name, type, classes, value, title);
            });
        }

        private URI getHref(Json.JObject obj, String name) {
            Option hrefString = obj.getAsString("href");
            if (!hrefString.isDefined()) {
                throw new SirenParseException(String.format("Missing required 'href' field in %s '%s'", name, obj));
            }
            return URI.create(hrefString.get());
        }

        private  List mapObjectList(Json.JArray list, Function f) {
            return list.getListAsObjects().map(f);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy