-
Notifications
You must be signed in to change notification settings - Fork 1.7k
De-duplicate identical classes and avoid __1
#1655
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 1 commit
c3fc589
28ce044
07c32d5
134518c
c80d0fd
f808794
155a6c0
950f33e
1d34bf5
c5b542a
c071e7a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| /** | ||
| * Copyright © 2024 Nokia | ||
| * | ||
| * 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 org.jsonschema2pojo.rules; | ||
|
|
||
| import com.fasterxml.jackson.databind.JsonNode; | ||
| import org.jsonschema2pojo.Schema; | ||
|
|
||
| import java.util.HashMap; | ||
| import java.util.Map; | ||
|
|
||
| /** | ||
| * Wraps an existing Rule and performs deduplication of identical schemas to the same output. | ||
| */ | ||
| class DeduplicateRule<T, R> implements Rule<T, R> { | ||
|
|
||
| private final Map<String, R> deduplicateCache; | ||
| private final Rule<T, R> rule; | ||
|
|
||
| public DeduplicateRule(Map<Class<?>, Map<String, ?>> dedupeCacheByRule, Rule<T, R> rule) { | ||
| // noinspection unchecked map is populated by us and guaranteed to be of the correct type | ||
| Map<String, R> dedupeCache = (Map<String, R>) dedupeCacheByRule.get(rule.getClass()); | ||
|
||
| if(dedupeCache == null) { | ||
| dedupeCache = new HashMap<>(); | ||
| dedupeCacheByRule.put(rule.getClass(), dedupeCache); | ||
| } | ||
| this.deduplicateCache = dedupeCache; | ||
| this.rule = rule; | ||
| } | ||
|
|
||
| /** | ||
| * Deduplicates based on {@link Schema#calculateHash()} and returns identical {@code R} instances. | ||
| * | ||
| * @param currentSchema | ||
| * schema to be used for deduplication | ||
| * @return same {@code R} instance if a previous schema with the same hash code was already processed | ||
| */ | ||
| @Override | ||
| public R apply(String nodeName, JsonNode node, JsonNode parent, T generatableType, Schema currentSchema) { | ||
|
||
| String hash = currentSchema.calculateHash(); | ||
| R output = deduplicateCache.get(hash); | ||
| if (output == null) { | ||
| output = rule.apply(nodeName, node, parent, generatableType, currentSchema); | ||
| deduplicateCache.put(hash, output); | ||
| } | ||
| return output; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -36,6 +36,9 @@ | |
| import com.sun.codemodel.JPackage; | ||
| import com.sun.codemodel.JType; | ||
|
|
||
| import java.util.HashMap; | ||
| import java.util.Map; | ||
|
|
||
| /** | ||
| * Provides factory/creation methods for the code generation rules. | ||
| */ | ||
|
|
@@ -47,6 +50,7 @@ public class RuleFactory { | |
| private GenerationConfig generationConfig; | ||
| private Annotator annotator; | ||
| private SchemaStore schemaStore; | ||
| private Map<Class<?>, Map<String, ?>> dedupeCache; | ||
|
||
|
|
||
| /** | ||
| * Create a new rule factory with the given generation config options. | ||
|
|
@@ -68,6 +72,7 @@ public RuleFactory(GenerationConfig generationConfig, Annotator annotator, Schem | |
| this.nameHelper = new NameHelper(generationConfig); | ||
| this.reflectionHelper = new ReflectionHelper(this); | ||
| this.logger = new NoopRuleLogger(); | ||
| this.dedupeCache = new HashMap<>(); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -116,7 +121,11 @@ public Rule<JDocCommentable, JDocComment> getCommentRule() { | |
| * @return a schema rule that can handle the "enum" declaration. | ||
| */ | ||
| public Rule<JClassContainer, JType> getEnumRule() { | ||
| return new EnumRule(this); | ||
| Rule<JClassContainer, JType> rule = new EnumRule(this); | ||
| if (generationConfig.isUseDeduplication()) { | ||
| rule = new DeduplicateRule<>(dedupeCache, rule); | ||
| } | ||
| return rule; | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -136,7 +145,11 @@ public Rule<JType, JType> getFormatRule() { | |
| * @return a schema rule that can handle the "object" declaration. | ||
| */ | ||
| public Rule<JPackage, JType> getObjectRule() { | ||
| return new ObjectRule(this, new ParcelableHelper(), reflectionHelper); | ||
| Rule<JPackage, JType> rule = new ObjectRule(this, new ParcelableHelper(), reflectionHelper); | ||
| if (generationConfig.isUseDeduplication()) { | ||
| rule = new DeduplicateRule<>(dedupeCache, rule); | ||
|
||
| } | ||
| return rule; | ||
| } | ||
|
|
||
| /** | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| /** | ||
| * Copyright © 2024 Nokia | ||
| * | ||
| * 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 org.jsonschema2pojo.rules; | ||
|
|
||
| import com.fasterxml.jackson.databind.JsonNode; | ||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||
| import com.fasterxml.jackson.databind.node.ArrayNode; | ||
| import com.fasterxml.jackson.databind.node.ObjectNode; | ||
| import com.google.common.collect.ImmutableMap; | ||
| import com.sun.codemodel.JCodeModel; | ||
| import com.sun.codemodel.JPackage; | ||
| import com.sun.codemodel.JType; | ||
| import org.jsonschema2pojo.Annotator; | ||
| import org.jsonschema2pojo.RuleLogger; | ||
| import org.jsonschema2pojo.Schema; | ||
| import org.jsonschema2pojo.util.NameHelper; | ||
| import org.junit.Before; | ||
| import org.junit.Test; | ||
| import org.mockito.ArgumentMatchers; | ||
| import org.mockito.stubbing.Answer; | ||
|
|
||
| import java.util.HashMap; | ||
| import java.util.Map; | ||
| import java.util.UUID; | ||
|
|
||
| import static org.hamcrest.MatcherAssert.assertThat; | ||
| import static org.hamcrest.Matchers.is; | ||
| import static org.junit.Assert.assertEquals; | ||
| import static org.junit.Assert.assertNotEquals; | ||
| import static org.mockito.Mockito.*; | ||
|
|
||
| public class DeduplicateRuleTest { | ||
|
|
||
| private Map<String, UUID> dedupeCache; | ||
| private Rule<Object, UUID> dedupeRule; | ||
|
|
||
| @Before | ||
| public void setupRule() { | ||
| dedupeCache = new HashMap<>(); | ||
| DummyRule dummyRule = new DummyRule(); | ||
| dedupeRule = new DeduplicateRule<>(ImmutableMap.of(dummyRule.getClass(), dedupeCache), dummyRule); | ||
| } | ||
|
|
||
| @Test | ||
| public void test() { | ||
|
|
||
| ObjectMapper objectMapper = new ObjectMapper(); | ||
|
|
||
| ArrayNode arrayNode1 = objectMapper.createArrayNode().add(7).add(8); | ||
| ArrayNode arrayNode2 = objectMapper.createArrayNode().add(7).add(8); | ||
| ArrayNode arrayNode3 = objectMapper.createArrayNode().add(7).add(9); | ||
| assertEquals(arrayNode1.toString(), arrayNode2.toString()); | ||
| assertNotEquals(arrayNode1.toString(), arrayNode3.toString()); | ||
|
|
||
| Schema schema1 = new Schema(null, arrayNode1, null); | ||
| Schema schema2 = new Schema(null, arrayNode2, null); | ||
| Schema schema3 = new Schema(null, arrayNode3, null); | ||
| assertEquals(schema1.calculateHash(), schema1.calculateHash()); | ||
| assertEquals(schema1.calculateHash(), schema2.calculateHash()); | ||
| assertNotEquals(schema1.calculateHash(), schema3.calculateHash()); | ||
|
|
||
| UUID uuid1 = dedupeRule.apply(null, null, null, null, schema1); | ||
| UUID uuid2 = dedupeRule.apply(null, null, null, null, schema1); | ||
| UUID uuid3 = dedupeRule.apply(null, null, null, null, schema2); | ||
| UUID uuid4 = dedupeRule.apply(null, null, null, null, schema3); | ||
|
|
||
| assertEquals(uuid1, uuid2); | ||
| assertEquals(uuid1, uuid3); | ||
| assertNotEquals(uuid1, uuid4); | ||
| } | ||
|
|
||
| public static class DummyRule implements Rule<Object, UUID> { | ||
| @Override | ||
| public UUID apply(String nodeName, JsonNode node, JsonNode parent, Object generatableType, Schema currentSchema) { | ||
| return UUID.randomUUID(); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| { | ||
| "aa" : { | ||
| "aaa" : "aaaa" | ||
| }, | ||
| "1" : { | ||
| "2" : {}, | ||
| "3" : [1, 2, 3] | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using SHA-256 of the compact JSON string for de-duplication.