diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..d4cd657
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,11 @@
+# To get started with Dependabot version updates, you'll need to specify which
+# package ecosystems to update and where the package manifests are located.
+# Please see the documentation for all configuration options:
+# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
+
+version: 2
+updates:
+ - package-ecosystem: "maven" # See documentation for possible values
+ directory: "/" # Location of package manifests
+ schedule:
+ interval: "weekly"
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..acf7261
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,23 @@
+name: CI
+
+on:
+ push:
+ branches:
+ - '**'
+ pull_request:
+ branches:
+ - '**'
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up JDK 17
+ uses: actions/setup-java@v2
+ with:
+ java-version: '17'
+ distribution: 'temurin'
+ - name: Build with Maven
+ run: ./mvnw --batch-mode clean verify
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e7d1631
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,54 @@
+# Created by .ignore support plugin (hsz.mobi)
+### JetBrains template
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff:
+.idea
+
+# Sensitive or high-churn files:
+.idea/dataSources.ids
+.idea/dataSources.xml
+.idea/dataSources.local.xml
+.idea/sqlDataSources.xml
+.idea/dynamic.xml
+.idea/uiDesigner.xml
+
+# Gradle:
+.idea/gradle.xml
+.idea/libraries
+
+# Mongo Explorer plugin:
+.idea/mongoSettings.xml
+
+## File-based project format:
+*.iws
+*.iml
+
+## Plugin-specific files:
+
+# IntelliJ
+/out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+### Maven template
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
+
diff --git a/.mvn/jvm.config b/.mvn/jvm.config
new file mode 100644
index 0000000..7cafa1e
--- /dev/null
+++ b/.mvn/jvm.config
@@ -0,0 +1 @@
+--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.text=ALL-UNNAMED --add-opens=java.desktop/java.awt.font=ALL-UNNAMED
diff --git a/.mvn/wrapper/.gitignore b/.mvn/wrapper/.gitignore
new file mode 100644
index 0000000..e72f5e8
--- /dev/null
+++ b/.mvn/wrapper/.gitignore
@@ -0,0 +1 @@
+maven-wrapper.jar
diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties
new file mode 100644
index 0000000..70e554c
--- /dev/null
+++ b/.mvn/wrapper/maven-wrapper.properties
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.1/apache-maven-3.8.1-bin.zip
+wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar
diff --git a/README.md b/README.md
index 8ddd85e..1e37c23 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,72 @@
-# json-schema-to-java-record
\ No newline at end of file
+[](https://github.com/Cosium/json-schema-to-java-record/actions/workflows/ci.yml)
+[](https://central.sonatype.com/artifact/com.cosium.json_schema_to_java_record/json-schema-to-java-record)
+
+# JSON Schema To Java Record
+
+An annotation processor converting JSON schemas to java records.
+
+# Quick start
+
+1. Import the BOM:
+ ```xml
+
+
+
+
+ com.cosium.json_schema_to_java_record
+ json-schema-to-java-record-bom
+ ${json-schema-to-java-record.version}
+ import
+ pom
+
+
+
+
+ ```
+2. Import the API:
+ ```xml
+
+
+
+ com.cosium.json_schema_to_java_record
+ json-schema-to-java-record-api
+
+
+
+ ```
+3. Import the annotation processor:
+ ```xml
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ com.cosium.json_schema_to_java_record
+ json-schema-to-java-record
+
+
+
+
+ ```
+4. Add your JSON schema files to the class path:
+ ```
+ src/main/resources/com/aqme
+ └── foo.schema.json
+ ```
+5. Annotate a `package-info.java` file like this:
+ ```java
+ @GenerateRecordsFromJsonSchemas(
+ schemaRootFileLocations =
+ @JsonSchemaFileLocation(
+ moduleAndPackage = "com.aqme",
+ relativeName = "foo.schema.json"
+ )
+ )
+ package com.aqme;
+
+ import com.cosium.json_schema_to_java_record_api.GenerateRecordsFromJsonSchemas;
+ import com.cosium.json_schema_to_java_record_api.JsonSchemaConfiguration;
+ import com.cosium.json_schema_to_java_record_api.JsonSchemaFileLocation;
+ ```
+6. Compile to generate the java files
\ No newline at end of file
diff --git a/api/pom.xml b/api/pom.xml
new file mode 100644
index 0000000..cb4c579
--- /dev/null
+++ b/api/pom.xml
@@ -0,0 +1,14 @@
+
+
+ 4.0.0
+
+
+ com.cosium.json_schema_to_java_record
+ json-schema-to-java-record-parent
+ 1.0-SNAPSHOT
+
+
+ JSON schema to Java Record API
+ json-schema-to-java-record-api
+
+
diff --git a/api/src/main/java/com/cosium/json_schema_to_java_record_api/GenerateRecordsFromJsonSchemas.java b/api/src/main/java/com/cosium/json_schema_to_java_record_api/GenerateRecordsFromJsonSchemas.java
new file mode 100644
index 0000000..602fed8
--- /dev/null
+++ b/api/src/main/java/com/cosium/json_schema_to_java_record_api/GenerateRecordsFromJsonSchemas.java
@@ -0,0 +1,15 @@
+package com.cosium.json_schema_to_java_record_api;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * @author Réda Housni Alaoui
+ */
+@Target({ElementType.PACKAGE})
+public @interface GenerateRecordsFromJsonSchemas {
+
+ JsonSchemaFileLocation[] schemaRootFileLocations();
+
+ JsonSchemaConfiguration[] schemaConfigurations() default {};
+}
diff --git a/api/src/main/java/com/cosium/json_schema_to_java_record_api/JsonSchemaConfiguration.java b/api/src/main/java/com/cosium/json_schema_to_java_record_api/JsonSchemaConfiguration.java
new file mode 100644
index 0000000..d827f67
--- /dev/null
+++ b/api/src/main/java/com/cosium/json_schema_to_java_record_api/JsonSchemaConfiguration.java
@@ -0,0 +1,25 @@
+package com.cosium.json_schema_to_java_record_api;
+
+/**
+ * @author Réda Housni Alaoui
+ */
+public @interface JsonSchemaConfiguration {
+
+ /**
+ * @return A value that should match the JSON schema $id attribute.
+ */
+ String schemaId();
+
+ /**
+ * Allows forcing the java type qualified name of the schema. If the type already exists, it will
+ * be used as is.
+ *
+ *
E.g. "com.aqme.Foo"
+ */
+ String javaTypeQualifiedName() default "";
+
+ /**
+ * @return The interfaces that the generated record must implement.
+ */
+ String[] javaInterfaceQualifiedNames() default {};
+}
diff --git a/api/src/main/java/com/cosium/json_schema_to_java_record_api/JsonSchemaFileLocation.java b/api/src/main/java/com/cosium/json_schema_to_java_record_api/JsonSchemaFileLocation.java
new file mode 100644
index 0000000..2dae4d9
--- /dev/null
+++ b/api/src/main/java/com/cosium/json_schema_to_java_record_api/JsonSchemaFileLocation.java
@@ -0,0 +1,16 @@
+package com.cosium.json_schema_to_java_record_api;
+
+/**
+ * @author Réda Housni Alaoui
+ */
+public @interface JsonSchemaFileLocation {
+ /**
+ * e.g. "com.aqme"
+ *
+ *
Use empty string "" for the root package
+ */
+ String moduleAndPackage();
+
+ /** e.g. "foo.schema.json" */
+ String relativeName();
+}
diff --git a/bom/pom.xml b/bom/pom.xml
new file mode 100644
index 0000000..d809d12
--- /dev/null
+++ b/bom/pom.xml
@@ -0,0 +1,31 @@
+
+
+ 4.0.0
+
+
+ com.cosium.json_schema_to_java_record
+ json-schema-to-java-record-parent
+ 1.0-SNAPSHOT
+
+
+ JSON schema to Java Record BOM
+ json-schema-to-java-record-bom
+
+ pom
+
+
+
+
+ ${project.groupId}
+ json-schema-to-java-record-api
+ ${project.version}
+
+
+ ${project.groupId}
+ json-schema-to-java-record
+ ${project.version}
+
+
+
+
+
diff --git a/core/pom.xml b/core/pom.xml
new file mode 100644
index 0000000..69c9804
--- /dev/null
+++ b/core/pom.xml
@@ -0,0 +1,48 @@
+
+
+ 4.0.0
+
+
+ com.cosium.json_schema_to_java_record
+ json-schema-to-java-record-parent
+ 1.0-SNAPSHOT
+
+
+ JSON schema to Java Record
+ json-schema-to-java-record
+
+
+
+ ${project.groupId}
+ json-schema-to-java-record-api
+ ${project.version}
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+
+ com.google.auto.service
+ auto-service
+ true
+
+
+
+ com.palantir.javapoet
+ javapoet
+
+
+
+ io.github.zenwave360
+ json-schema-ref-parser-jvm
+
+
+
+ com.cosium.logging
+ annotation-processor-logger
+
+
+
+
diff --git a/core/src/main/java/com/cosium/json_schema_to_java_record/$RefClasspathResolver.java b/core/src/main/java/com/cosium/json_schema_to_java_record/$RefClasspathResolver.java
new file mode 100644
index 0000000..74a7db1
--- /dev/null
+++ b/core/src/main/java/com/cosium/json_schema_to_java_record/$RefClasspathResolver.java
@@ -0,0 +1,47 @@
+package com.cosium.json_schema_to_java_record;
+
+import static java.util.Objects.requireNonNull;
+
+import io.zenwave360.jsonrefparser.$Ref;
+import io.zenwave360.jsonrefparser.resolver.Resolver;
+import java.io.InputStream;
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * @author Réda Housni Alaoui
+ */
+class $RefClasspathResolver implements Resolver {
+
+ private final ReadonlyClassPathResources classPathResources;
+
+ $RefClasspathResolver(ReadonlyClassPathResources classPathResources) {
+ this.classPathResources = requireNonNull(classPathResources);
+ }
+
+ @Override
+ public String resolve($Ref $ref) {
+ try {
+ URI uri = $ref.getURI();
+ if (uri.toString().startsWith("classpath:") && !uri.toString().startsWith("classpath:/")) {
+ // gracefully handle classpath: without the slash
+ uri = URI.create(uri.toString().replace("classpath:", "classpath:/"));
+ }
+
+ String uriPath = uri.getPath().replaceFirst("^/", "");
+ int lastIndexOfSlash = uriPath.lastIndexOf("/");
+
+ String packageName = uriPath.substring(0, lastIndexOfSlash).replace("/", ".");
+ String relativeName = uriPath.substring(lastIndexOfSlash + 1);
+ try (InputStream inputStream =
+ classPathResources.openInputStream(packageName, relativeName)) {
+ return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
+ }
+
+ } catch (MissingResourceException missingResourceException) {
+ throw missingResourceException;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/core/src/main/java/com/cosium/json_schema_to_java_record/AnnotationProcessor.java b/core/src/main/java/com/cosium/json_schema_to_java_record/AnnotationProcessor.java
new file mode 100644
index 0000000..6b6a003
--- /dev/null
+++ b/core/src/main/java/com/cosium/json_schema_to_java_record/AnnotationProcessor.java
@@ -0,0 +1,74 @@
+package com.cosium.json_schema_to_java_record;
+
+import com.cosium.json_schema_to_java_record_api.GenerateRecordsFromJsonSchemas;
+import com.cosium.logging.annotation_processor.AbstractLoggingProcessor;
+import com.google.auto.service.AutoService;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.Processor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.TypeElement;
+import org.jspecify.annotations.Nullable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Réda Housni Alaoui
+ */
+@AutoService(Processor.class)
+public class AnnotationProcessor extends AbstractLoggingProcessor {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(AnnotationProcessor.class);
+
+ private static final Boolean ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS = false;
+
+ private final Set processedCommands = new CopyOnWriteArraySet<>();
+
+ @Nullable private JavaTypes javaTypes;
+ @Nullable private JsonSchemas jsonSchemas;
+
+ @Override
+ public synchronized void init(ProcessingEnvironment processingEnv) {
+ super.init(processingEnv);
+ this.javaTypes = new JavaTypes(processingEnv.getFiler());
+ jsonSchemas = new JsonSchemas(new ReadonlyClassPathResources(processingEnv.getFiler()));
+ }
+
+ @Override
+ protected boolean doProcess(Set extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ if (roundEnv.processingOver() || annotations.isEmpty()) {
+ return ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS;
+ }
+
+ Set commands =
+ roundEnv.getElementsAnnotatedWith(GenerateRecordsFromJsonSchemas.class).stream()
+ .map(
+ element ->
+ new Command(
+ element, element.getAnnotation(GenerateRecordsFromJsonSchemas.class)))
+ .filter(Predicate.not(processedCommands::contains))
+ .collect(Collectors.toUnmodifiableSet());
+
+ commands.stream()
+ .peek(command -> LOGGER.debug("Executing {}", command))
+ .forEach(command -> command.execute(javaTypes, jsonSchemas));
+
+ processedCommands.addAll(commands);
+
+ return ALLOW_OTHER_PROCESSORS_TO_CLAIM_ANNOTATIONS;
+ }
+
+ @Override
+ public Set getSupportedAnnotationTypes() {
+ return Set.of(GenerateRecordsFromJsonSchemas.class.getCanonicalName());
+ }
+
+ @Override
+ public SourceVersion getSupportedSourceVersion() {
+ return SourceVersion.latestSupported();
+ }
+}
diff --git a/core/src/main/java/com/cosium/json_schema_to_java_record/Command.java b/core/src/main/java/com/cosium/json_schema_to_java_record/Command.java
new file mode 100644
index 0000000..2680d92
--- /dev/null
+++ b/core/src/main/java/com/cosium/json_schema_to_java_record/Command.java
@@ -0,0 +1,39 @@
+package com.cosium.json_schema_to_java_record;
+
+import static java.util.Objects.requireNonNull;
+
+import com.cosium.json_schema_to_java_record_api.GenerateRecordsFromJsonSchemas;
+import java.util.Arrays;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.PackageElement;
+
+/**
+ * @author Réda Housni Alaoui
+ */
+record Command(Element annotatedElement, GenerateRecordsFromJsonSchemas annotation) {
+
+ public Command {
+ requireNonNull(annotatedElement);
+ requireNonNull(annotation);
+ }
+
+ public void execute(JavaTypes javaTypes, JsonSchemas jsonSchemas) {
+ Configuration configuration = new Configuration(annotatedElementPackageName(), annotation);
+
+ Arrays.stream(annotation.schemaRootFileLocations())
+ .map(jsonSchemas::parse)
+ .forEach(jsonSchema -> jsonSchema.writeJavaType(javaTypes, configuration));
+ }
+
+ private String annotatedElementPackageName() {
+
+ Element visitedElement = annotatedElement;
+ while (visitedElement != null) {
+ if (visitedElement instanceof PackageElement packageElement) {
+ return packageElement.getQualifiedName().toString();
+ }
+ visitedElement = visitedElement.getEnclosingElement();
+ }
+ return "";
+ }
+}
diff --git a/core/src/main/java/com/cosium/json_schema_to_java_record/Configuration.java b/core/src/main/java/com/cosium/json_schema_to_java_record/Configuration.java
new file mode 100644
index 0000000..1ef152e
--- /dev/null
+++ b/core/src/main/java/com/cosium/json_schema_to_java_record/Configuration.java
@@ -0,0 +1,35 @@
+package com.cosium.json_schema_to_java_record;
+
+import static java.util.Objects.requireNonNull;
+
+import com.cosium.json_schema_to_java_record_api.GenerateRecordsFromJsonSchemas;
+import com.cosium.json_schema_to_java_record_api.JsonSchemaConfiguration;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * @author Réda Housni Alaoui
+ */
+class Configuration {
+
+ private final String rootPackage;
+ private final Map map;
+
+ public Configuration(String rootPackage, GenerateRecordsFromJsonSchemas annotation) {
+ this.rootPackage = requireNonNull(rootPackage);
+ map =
+ Arrays.stream(annotation.schemaConfigurations())
+ .collect(Collectors.toMap(JsonSchemaConfiguration::schemaId, Function.identity()));
+ }
+
+ public String rootPackage() {
+ return rootPackage;
+ }
+
+ public Optional bySchemaId(String schemaId) {
+ return Optional.ofNullable(map.get(schemaId));
+ }
+}
diff --git a/core/src/main/java/com/cosium/json_schema_to_java_record/JavaTypes.java b/core/src/main/java/com/cosium/json_schema_to_java_record/JavaTypes.java
new file mode 100644
index 0000000..6055748
--- /dev/null
+++ b/core/src/main/java/com/cosium/json_schema_to_java_record/JavaTypes.java
@@ -0,0 +1,64 @@
+package com.cosium.json_schema_to_java_record;
+
+import static java.util.Objects.requireNonNull;
+
+import com.cosium.json_schema_to_java_record_api.GenerateRecordsFromJsonSchemas;
+import com.palantir.javapoet.AnnotationSpec;
+import com.palantir.javapoet.ClassName;
+import com.palantir.javapoet.JavaFile;
+import com.palantir.javapoet.TypeSpec;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import javax.annotation.processing.Filer;
+import javax.annotation.processing.FilerException;
+import javax.annotation.processing.Generated;
+import javax.tools.StandardLocation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Réda Housni Alaoui
+ */
+class JavaTypes {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(JavaTypes.class);
+
+ private final Filer filer;
+
+ JavaTypes(Filer filer) {
+ this.filer = requireNonNull(filer);
+ }
+
+ public boolean existsOnClassPath(ClassName className) {
+ try {
+ filer.getResource(
+ StandardLocation.CLASS_PATH, className.packageName(), className.simpleName() + ".class");
+ return true;
+ } catch (IOException | IllegalArgumentException e) {
+ return false;
+ }
+ }
+
+ public void write(String packageName, TypeSpec.Builder typeSpecBuilder) {
+ typeSpecBuilder.addAnnotation(
+ AnnotationSpec.builder(Generated.class)
+ .addMember("value", "$S", GenerateRecordsFromJsonSchemas.class.getName())
+ .build());
+ write(JavaFile.builder(packageName, typeSpecBuilder.build()).build());
+ }
+
+ private void write(JavaFile javaFile) {
+ LOGGER.debug("Writing {}", javaFile);
+ try {
+ javaFile.writeTo(filer);
+ } catch (FilerException e) {
+ if (e.getMessage().contains("Attempt to recreate a file")) {
+ LOGGER.debug("{} already exists. Skipping write.", javaFile);
+ return;
+ }
+ throw new UncheckedIOException(e);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+}
diff --git a/core/src/main/java/com/cosium/json_schema_to_java_record/JsonSchema.java b/core/src/main/java/com/cosium/json_schema_to_java_record/JsonSchema.java
new file mode 100644
index 0000000..9523f71
--- /dev/null
+++ b/core/src/main/java/com/cosium/json_schema_to_java_record/JsonSchema.java
@@ -0,0 +1,41 @@
+package com.cosium.json_schema_to_java_record;
+
+import static java.util.Objects.requireNonNull;
+
+import com.palantir.javapoet.ClassName;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Réda Housni Alaoui
+ */
+record JsonSchema(String fileRelativeName, JsonSchemaContent content) {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(JsonSchema.class);
+
+ JsonSchema {
+ requireNonNull(fileRelativeName);
+ requireNonNull(content);
+ }
+
+ public void writeJavaType(JavaTypes javaTypes, Configuration configuration) {
+ LOGGER.debug("Writing java types of {}", this);
+ content.writeJavaType(
+ javaTypes, configuration, createDefaultJavaClassName(configuration), false);
+ }
+
+ private ClassName createDefaultJavaClassName(Configuration configuration) {
+
+ return ClassName.get(
+ configuration.rootPackage(),
+ Stream.of(fileRelativeName.split("\\.")[0].split("-"))
+ .map(this::capitalize)
+ .collect(Collectors.joining("")));
+ }
+
+ private String capitalize(String text) {
+ return text.substring(0, 1).toUpperCase() + text.substring(1).toLowerCase();
+ }
+}
diff --git a/core/src/main/java/com/cosium/json_schema_to_java_record/JsonSchemaContent.java b/core/src/main/java/com/cosium/json_schema_to_java_record/JsonSchemaContent.java
new file mode 100644
index 0000000..7704318
--- /dev/null
+++ b/core/src/main/java/com/cosium/json_schema_to_java_record/JsonSchemaContent.java
@@ -0,0 +1,238 @@
+package com.cosium.json_schema_to_java_record;
+
+import com.cosium.json_schema_to_java_record_api.JsonSchemaConfiguration;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.palantir.javapoet.AnnotationSpec;
+import com.palantir.javapoet.ClassName;
+import com.palantir.javapoet.MethodSpec;
+import com.palantir.javapoet.ParameterSpec;
+import com.palantir.javapoet.ParameterizedTypeName;
+import com.palantir.javapoet.TypeName;
+import com.palantir.javapoet.TypeSpec;
+import java.net.URI;
+import java.time.ZonedDateTime;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import javax.lang.model.element.Modifier;
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Réda Housni Alaoui
+ */
+record JsonSchemaContent(
+ @Nullable String $schema,
+ @Nullable String $id,
+ Type type,
+ @Nullable String format,
+ @Nullable JsonSchemaContent items,
+ @Nullable Set