diff --git a/CedarJava/src/main/java/com/cedarpolicy/CedarJson.java b/CedarJava/src/main/java/com/cedarpolicy/CedarJson.java index 6e5b6b0..a2301ac 100644 --- a/CedarJava/src/main/java/com/cedarpolicy/CedarJson.java +++ b/CedarJava/src/main/java/com/cedarpolicy/CedarJson.java @@ -16,7 +16,11 @@ package com.cedarpolicy; +import com.cedarpolicy.model.entity.Entity; +import com.cedarpolicy.model.schema.Schema; import com.cedarpolicy.model.slice.Slice; +import com.cedarpolicy.serializer.EntitySerializer; +import com.cedarpolicy.serializer.SchemaSerializer; import com.cedarpolicy.serializer.SliceSerializer; import com.cedarpolicy.serializer.ValueDeserializer; import com.cedarpolicy.serializer.ValueSerializer; @@ -50,6 +54,8 @@ private static ObjectMapper createObjectMapper() { final ObjectMapper mapper = new ObjectMapper(); final SimpleModule module = new SimpleModule(); + module.addSerializer(Entity.class, new EntitySerializer()); + module.addSerializer(Schema.class, new SchemaSerializer()); module.addSerializer(Slice.class, new SliceSerializer()); module.addSerializer(Value.class, new ValueSerializer()); module.addDeserializer(Value.class, new ValueDeserializer()); diff --git a/CedarJava/src/main/java/com/cedarpolicy/model/policy/Policy.java b/CedarJava/src/main/java/com/cedarpolicy/model/policy/Policy.java index edfaea5..aec78c7 100644 --- a/CedarJava/src/main/java/com/cedarpolicy/model/policy/Policy.java +++ b/CedarJava/src/main/java/com/cedarpolicy/model/policy/Policy.java @@ -60,6 +60,20 @@ public Policy( this.policyID = policyID; } + /** + * Get the policy ID. + */ + public String getID() { + return policyID; + } + + /** + * Get the policy source. + */ + public String getSource() { + return policySrc; + } + @Override public String toString() { return "// Policy ID: " + policyID + "\n" + policySrc; diff --git a/CedarJava/src/main/java/com/cedarpolicy/model/policy/PolicySet.java b/CedarJava/src/main/java/com/cedarpolicy/model/policy/PolicySet.java index 9658e07..7d4694f 100644 --- a/CedarJava/src/main/java/com/cedarpolicy/model/policy/PolicySet.java +++ b/CedarJava/src/main/java/com/cedarpolicy/model/policy/PolicySet.java @@ -22,8 +22,9 @@ import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Set; - +import java.util.stream.Collectors; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -67,6 +68,24 @@ public PolicySet(Set policies, Set templates, List this.templateLinks = templateLinks; } + /** + * Get the static policies in the policy set. + * + * @return A map from policy id to `Policy` object + */ + public Map getStaticPolicies() { + return policies.stream().collect(Collectors.toMap(Policy::getID, Policy::getSource)); + } + + /** + * Get the templates in the policy set. + * + * @return A map from policy id to `Policy` object + */ + public Map getTemplates() { + return templates.stream().collect(Collectors.toMap(Policy::getID, Policy::getSource)); + } + /** * Parse multiple policies and templates from a file into a PolicySet. * @param filePath the path to the file containing the policies diff --git a/CedarJava/src/main/java/com/cedarpolicy/model/schema/Schema.java b/CedarJava/src/main/java/com/cedarpolicy/model/schema/Schema.java index 292a7cc..ce4e7e3 100644 --- a/CedarJava/src/main/java/com/cedarpolicy/model/schema/Schema.java +++ b/CedarJava/src/main/java/com/cedarpolicy/model/schema/Schema.java @@ -18,10 +18,8 @@ import com.cedarpolicy.loader.LibraryLoader; import com.cedarpolicy.model.exception.InternalException; -import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import java.util.Optional; @@ -36,13 +34,12 @@ public final class Schema { } /** Is this schema in the JSON or human format */ - @JsonIgnore public final JsonOrHuman type; + /** This will be present if and only if `type` is `Json`. */ - @JsonProperty("json") - private final Optional schemaJson; + public final Optional schemaJson; + /** This will be present if and only if `type` is `Human`. */ - @JsonProperty("human") public final Optional schemaText; /** diff --git a/CedarJava/src/main/java/com/cedarpolicy/model/slice/BasicSlice.java b/CedarJava/src/main/java/com/cedarpolicy/model/slice/BasicSlice.java index 2ae2a4d..3132393 100644 --- a/CedarJava/src/main/java/com/cedarpolicy/model/slice/BasicSlice.java +++ b/CedarJava/src/main/java/com/cedarpolicy/model/slice/BasicSlice.java @@ -20,7 +20,6 @@ import com.cedarpolicy.model.policy.Policy; import com.cedarpolicy.model.policy.TemplateLink; import com.cedarpolicy.value.Value; -import com.fasterxml.jackson.annotation.JsonProperty; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.*; @@ -37,10 +36,8 @@ public class BasicSlice implements Slice { private final Set entities; - @JsonProperty("templatePolicies") private final Map templatePolicies; - @JsonProperty("templateInstantiations") private final List templateLinks; /** diff --git a/CedarJava/src/main/java/com/cedarpolicy/serializer/EntitySerializer.java b/CedarJava/src/main/java/com/cedarpolicy/serializer/EntitySerializer.java new file mode 100644 index 0000000..4118c19 --- /dev/null +++ b/CedarJava/src/main/java/com/cedarpolicy/serializer/EntitySerializer.java @@ -0,0 +1,42 @@ +/* + * Copyright 2022-2023 Amazon.com, Inc. or its affiliates. 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 + * + * https://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.cedarpolicy.serializer; + +import com.cedarpolicy.model.entity.Entity; +import com.cedarpolicy.value.EntityUID; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import java.io.IOException; +import java.util.stream.Collectors; + +/** Serialize an entity. */ +public class EntitySerializer extends JsonSerializer { + + /** Serialize an entity. */ + @Override + public void serialize( + Entity entity, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) + throws IOException { + jsonGenerator.writeStartObject(); + jsonGenerator.writeObjectField("uid", entity.getEUID().asJson()); + jsonGenerator.writeObjectField("attrs", entity.attrs); + jsonGenerator.writeObjectField("parents", + entity.getParents().stream().map(EntityUID::asJson).collect(Collectors.toSet())); + jsonGenerator.writeEndObject(); + } +} diff --git a/CedarJava/src/main/java/com/cedarpolicy/serializer/JsonEUID.java b/CedarJava/src/main/java/com/cedarpolicy/serializer/JsonEUID.java index 5146001..8a136f8 100644 --- a/CedarJava/src/main/java/com/cedarpolicy/serializer/JsonEUID.java +++ b/CedarJava/src/main/java/com/cedarpolicy/serializer/JsonEUID.java @@ -20,14 +20,10 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.cedarpolicy.value.EntityUID; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; /** Represent JSON format of Entity Unique Identifier. */ -@JsonDeserialize -@JsonSerialize public class JsonEUID { /** euid (__entity is used as escape sequence in JSON). */ @JsonProperty("type") diff --git a/CedarJava/src/main/java/com/cedarpolicy/serializer/SchemaSerializer.java b/CedarJava/src/main/java/com/cedarpolicy/serializer/SchemaSerializer.java new file mode 100644 index 0000000..96c7904 --- /dev/null +++ b/CedarJava/src/main/java/com/cedarpolicy/serializer/SchemaSerializer.java @@ -0,0 +1,42 @@ +/* + * Copyright 2022-2023 Amazon.com, Inc. or its affiliates. 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 + * + * https://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.cedarpolicy.serializer; + +import com.cedarpolicy.model.schema.Schema; +import com.cedarpolicy.model.schema.Schema.JsonOrHuman; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import java.io.IOException; + +/** Serialize a schema. */ +public class SchemaSerializer extends JsonSerializer { + + /** Serialize a schema. */ + @Override + public void serialize( + Schema schema, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) + throws IOException { + jsonGenerator.writeStartObject(); + if (schema.type == JsonOrHuman.Json) { + jsonGenerator.writeObjectField("json", schema.schemaJson.get()); + } else { + jsonGenerator.writeStringField("human", schema.schemaText.get()); + } + jsonGenerator.writeEndObject(); + } +} diff --git a/CedarJava/src/main/java/com/cedarpolicy/serializer/SliceSerializer.java b/CedarJava/src/main/java/com/cedarpolicy/serializer/SliceSerializer.java index 46735f7..4ae98f3 100644 --- a/CedarJava/src/main/java/com/cedarpolicy/serializer/SliceSerializer.java +++ b/CedarJava/src/main/java/com/cedarpolicy/serializer/SliceSerializer.java @@ -16,18 +16,11 @@ package com.cedarpolicy.serializer; -import com.cedarpolicy.model.entity.Entity; import com.cedarpolicy.model.slice.Slice; -import com.cedarpolicy.value.Value; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.IOException; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; /** Serialize a slice. Only used internally by CedarJson */ public class SliceSerializer extends JsonSerializer { @@ -39,36 +32,10 @@ public void serialize( throws IOException { jsonGenerator.writeStartObject(); jsonGenerator.writeObjectField("policies", slice.getPolicies()); - jsonGenerator.writeObjectField( - "entities", convertEntitiesToJsonEntities(slice.getEntities())); + jsonGenerator.writeObjectField("entities", slice.getEntities()); jsonGenerator.writeObjectField("templates", slice.getTemplates()); jsonGenerator.writeObjectField( "templateInstantiations", slice.getTemplateLinks()); jsonGenerator.writeEndObject(); } - - private static class JsonEntity { - /** Entity uid for the entity. */ - @SuppressFBWarnings public final JsonEUID uid; - - /** Entity attributes, where the value string is a Cedar literal value. */ - @SuppressFBWarnings public final Map attrs; - - /** Set of direct parent entities of this entity. */ - public final Set parents; - - JsonEntity(Entity e) { - this.uid = e.getEUID().asJson(); - this.attrs = e.attrs; - this.parents = e.getParents().stream().map(euid -> euid.asJson()).collect(Collectors.toSet()); - } - } - - Set convertEntitiesToJsonEntities(Set entities) { - Set ret = new HashSet(); - for (Entity entity : entities) { - ret.add(new JsonEntity(entity)); - } - return ret; - } } diff --git a/CedarJava/src/test/java/com/cedarpolicy/JSONTests.java b/CedarJava/src/test/java/com/cedarpolicy/JSONTests.java index f6eb92d..2e13dc5 100644 --- a/CedarJava/src/test/java/com/cedarpolicy/JSONTests.java +++ b/CedarJava/src/test/java/com/cedarpolicy/JSONTests.java @@ -166,7 +166,7 @@ public void testEntityUID() { ObjectNode inner = JsonNodeFactory.instance.objectNode(); inner.put("id", "jakob"); inner.put("type", "silver"); - n.put(ENTITY_ESCAPE_SEQ, inner); + n.replace(ENTITY_ESCAPE_SEQ, inner); assertJSONEqual(n, uid); String invalidNamespace = "Us,er::\"alice\""; @@ -181,7 +181,7 @@ public void testEntityUID() { inner = JsonNodeFactory.instance.objectNode(); inner.put("id", "ali\"ce"); inner.put("type", "User"); - n.put(ENTITY_ESCAPE_SEQ, inner); + n.replace(ENTITY_ESCAPE_SEQ, inner); assertJSONEqual(n, uid); String weirdType = "a"; @@ -191,7 +191,7 @@ public void testEntityUID() { inner = JsonNodeFactory.instance.objectNode(); inner.put("id", weirdId); inner.put("type", weirdType); - n.put(ENTITY_ESCAPE_SEQ, inner); + n.replace(ENTITY_ESCAPE_SEQ, inner); assertJSONEqual(n, uid); } @@ -200,7 +200,7 @@ private ObjectNode buildEuidObject(String type, String id) { var inner = JsonNodeFactory.instance.objectNode(); inner.put("id", id); inner.put("type", type); - n.put(ENTITY_ESCAPE_SEQ, inner); + n.replace(ENTITY_ESCAPE_SEQ, inner); return n; } @@ -213,7 +213,7 @@ public void testLongEntityUID() { ObjectNode inner = JsonNodeFactory.instance.objectNode(); inner.put("id", "donut"); inner.put("type", "long::john::silver"); - n.put(ENTITY_ESCAPE_SEQ, inner); + n.replace(ENTITY_ESCAPE_SEQ, inner); assertJSONEqual(n, uid); } diff --git a/CedarJava/src/test/java/com/cedarpolicy/SharedIntegrationTests.java b/CedarJava/src/test/java/com/cedarpolicy/SharedIntegrationTests.java index 7998f65..200f60e 100644 --- a/CedarJava/src/test/java/com/cedarpolicy/SharedIntegrationTests.java +++ b/CedarJava/src/test/java/com/cedarpolicy/SharedIntegrationTests.java @@ -38,7 +38,6 @@ import com.cedarpolicy.serializer.JsonEUID; import com.cedarpolicy.value.Value; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.FileInputStream; @@ -91,7 +90,6 @@ private Path resolveIntegrationTestPath(String path) { * populated by Jackson when the test files are deserialized. */ @SuppressWarnings("visibilitymodifier") - @JsonDeserialize private static class JsonTest { /** * File name of the file containing policies. Path is relative to the integration tests @@ -123,7 +121,6 @@ private static class JsonTest { /** Directly corresponds to the structure of a request in the JSON formatted tests files. */ @SuppressWarnings("visibilitymodifier") - @JsonDeserialize private static class JsonRequest { /** Textual description of the request. */ public String description; @@ -159,7 +156,6 @@ private static class JsonRequest { * String, rather than String to Values. */ @SuppressWarnings("visibilitymodifier") - @JsonDeserialize private static class JsonEntity { /** Entity uid for the entity. */ @SuppressFBWarnings(