Skip to content
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

Inmutable schemas #269

Open
jgonzalezlawyer opened this issue Aug 18, 2023 · 1 comment
Open

Inmutable schemas #269

jgonzalezlawyer opened this issue Aug 18, 2023 · 1 comment
Assignees

Comments

@jgonzalezlawyer
Copy link

Hi,

I propose generate inmutable classes for messages:

Thanks

templateSchema.ftlh
package ${packageModel}.${schema.parentPackage};

import java.util.Objects;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Builder;
import lombok.Value;
<#list schema.fieldObjectList as field>
<#if field.dataType?has_content && field.dataTypeSimple == "enum">
import com.fasterxml.jackson.annotation.JsonValue;
<#break>
</#if>
</#list>
import io.swagger.v3.oas.annotations.media.Schema;
<#list schema.importList as import>
import ${import};
</#list>
<#list schema.fieldObjectList as field>
<#if field.restrictions.maxLength?has_content || field.restrictions.minLength?has_content>
import ${packageModel}.customvalidator.Size;
<#break>
</#if>
</#list>
<#list schema.fieldObjectList as field>
<#if field.restrictions.maximum?has_content>
import ${packageModel}.customvalidator.Max;
<#break>
</#if>
</#list>
<#list schema.fieldObjectList as field>
<#if field.restrictions.minimum?has_content>
import ${packageModel}.customvalidator.Min;
<#break>
</#if>
</#list>
<#list schema.fieldObjectList as field>
<#if field.restrictions.maxItems?has_content>
import ${packageModel}.customvalidator.MaxItems;
<#break>
</#if>
</#list>
<#list schema.fieldObjectList as field>
<#if field.restrictions.minItems?has_content>
import ${packageModel}.customvalidator.MinItems;
<#break>
</#if>
</#list>
<#list schema.fieldObjectList as field>
<#if field.required || schema.schemaCombinator == "anyOf" || schema.schemaCombinator == "oneOf">
import ${exceptionPackage}.exception.ModelClassException;
<#break>
</#if>
</#list>
<#list schema.fieldObjectList as field>
<#if field.restrictions.pattern?has_content>
import ${packageModel}.customvalidator.Pattern;
<#break>
</#if>
</#list>
<#list schema.fieldObjectList as field>
<#if field.restrictions.multipleOf?has_content>
import ${packageModel}.customvalidator.MultipleOf;
<#break>
</#if>
</#list>
<#list schema.fieldObjectList as field>
<#if field.required?has_content && field.required == true>
import ${packageModel}.customvalidator.NotNull;
<#break>
</#if>
</#list>
<#list schema.fieldObjectList as field>
<#if field.restrictions.uniqueItems?has_content && field.restrictions.uniqueItems == true>
import ${packageModel}.customvalidator.UniqueItems;
<#break>
</#if>
</#list>

@value
@builder
@JsonDeserialize(builder = ${schema.className}.${schema.className}Builder.class)
public class ${schema.className} {

<#list schema.fieldObjectList as field>
@JsonProperty(value ="${field.baseName?uncap_first}")
<#if field.restrictions.minimum?has_content && (!field.restrictions.exclusiveMinimum?has_content || field.restrictions.exclusiveMinimum == false)>
@min(minimum = "${field.restrictions.minimum}", exclusive = false)
</#if>
<#if field.restrictions.minimum?has_content && field.restrictions.exclusiveMinimum?has_content && field.restrictions.exclusiveMinimum == true>
@min(minimum = "${field.restrictions.minimum}", exclusive = ${field.restrictions.exclusiveMinimum?string})
</#if>
<#if field.restrictions.maximum?has_content && (!field.restrictions.exclusiveMaximum?has_content || field.restrictions.exclusiveMaximum == false)>
@max(maximum = "${field.restrictions.maximum}", exclusive = false)
</#if>
<#if field.restrictions.maximum?has_content && field.restrictions.exclusiveMaximum?has_content && field.restrictions.exclusiveMaximum == true>
@max(maximum = "${field.restrictions.maximum}", exclusive = ${field.restrictions.exclusiveMaximum?string})
</#if>
<#if field.restrictions.maxItems?has_content>
@Maxitems(maximum = ${field.restrictions.maxItems})
</#if>
<#if field.restrictions.minItems?has_content>
@MinItems(minimum = ${field.restrictions.minItems})
</#if>
<#if field.restrictions.uniqueItems?has_content && field.restrictions.uniqueItems == true>
@Uniqueitems
</#if>
<#if field.restrictions.maxLength?has_content && field.restrictions.minLength?has_content>
@SiZe(min =${field.restrictions.minLength}, max =${field.restrictions.maxLength})
<#elseif field.restrictions.maxLength?has_content && !field.restrictions.minLength?has_content>
@SiZe(max =${field.restrictions.maxLength})
<#elseif !field.restrictions.maxLength?has_content && field.restrictions.minLength?has_content>
@SiZe(min =${field.restrictions.minLength})
</#if>
<#if field.restrictions.pattern?has_content>
@pattern(regex = "${field.restrictions.pattern}")
</#if>
<#if field.restrictions.multipleOf?has_content>
@MultipleOf(multiple = "${field.restrictions.multipleOf}")
</#if>
<#if field.required?has_content && field.required == true>
@NotNull
</#if>
<#if field.dataType?has_content && (field.dataTypeSimple == "array" || field.dataTypeSimple == "Array")>
<#if field.required>
private final List<<#if field.parentPackage??>${packageModel}.${field.parentPackage}.</#if>${field.dataType}> ${field.baseName?uncap_first};
<#else>
private List<<#if field.parentPackage??>${packageModel}.${field.parentPackage}.</#if>${field.dataType}> ${field.baseName?uncap_first} = new ArrayList<<#if field.parentPackage??>${packageModel}.${field.parentPackage}.</#if>${field.dataType}>();
</#if>
<#elseif field.dataType?has_content && field.dataTypeSimple == "map">
<#if field.required>
private final Map<String, ${field.dataType}> ${field.baseName?uncap_first};
<#else>
private Map<String, <#if field.parentPackage??>${packageModel}.${field.parentPackage}.</#if>${field.dataType}> ${field.baseName?uncap_first} = new HashMap<String, <#if field.parentPackage??>${packageModel}.${field.parentPackage}.</#if>${field.dataType}>();
</#if>
<#elseif field.dataType?has_content && field.dataTypeSimple == "enum">
<#if field.required>
private final ${field.baseName?cap_first} ${field.baseName?uncap_first};
<#else>
private ${field.baseName?cap_first} ${field.baseName?uncap_first};
</#if>
public enum ${field.baseName?cap_first} {
<#list field.enumValues as value>
${value?upper_case}("${value?no_esc}")<#sep>,
</#list>;

private ${field.dataType?cap_first} value;

${field.baseName?cap_first}(${field.dataType?cap_first} value) {
  this.value = value;
}

@JsonValue
public ${field.dataType?cap_first} getValue() {
  return value;
}

@Override
public String toString() {
  return String.valueOf(value);
}

}
<#elseif field.dataTypeSimple?has_content>
<#if field.required>
<#if field.parentPackage??>
private final ${packageModel}.${field.parentPackage}.${field.dataTypeSimple} ${field.baseName?uncap_first};
<#else>
private final ${field.dataTypeSimple?cap_first} ${field.baseName?uncap_first};
</#if>
<#elseif field.parentPackage??>
private ${packageModel}.${field.parentPackage}.${field.dataTypeSimple} ${field.baseName?uncap_first};
<#else>
private ${field.dataTypeSimple?cap_first} ${field.baseName?uncap_first};
</#if>
</#if>
</#list>

private ${schema.className}(<@compress single_line=true><#list schema.fieldObjectList as field>
<#if field.dataType?has_content && field.dataTypeSimple == "enum">${field.baseName?cap_first} ${field.baseName?uncap_first}<#elseif field.dataType?has_content && field.dataTypeSimple == "array">List<<#if field.parentPackage??>${packageModel}.${field.parentPackage}.</#if>${field.dataType}> ${field.baseName?uncap_first}<#elseif field.dataType?has_content && field.dataTypeSimple == "map">Map<String, ${field.dataType}> ${field.baseName?uncap_first}<#else><#if field.parentPackage??>${packageModel}.${field.parentPackage}.${field.dataTypeSimple?cap_first}<#else>${field.dataTypeSimple?cap_first}</#if> ${field.baseName?uncap_first}</#if><#sep>, </#list>) {/@compress
<#list schema.fieldObjectList as field>
this.${field.baseName?uncap_first} = ${field.baseName?uncap_first};
</#list>

<#list schema.fieldObjectList as field>
  <#if field.required>
validateRequiredAttributes();
  <#break>
  </#if>
</#list>
<#if schema.schemaCombinator == "anyOf" || schema.schemaCombinator == "oneOf">
validatePartialCombinations();
</#if>

}

private ${schema.className}(${schema.className}Builder builder) {
<#list schema.fieldObjectList as field>
this.${field.baseName?uncap_first} = builder.${field.baseName?uncap_first};
</#list>

<#list schema.fieldObjectList as field>
<#if field.required>
validateRequiredAttributes();
<#break>
</#if>
</#list>
<#if schema.schemaCombinator == "anyOf" || schema.schemaCombinator == "oneOf">
validatePartialCombinations();
</#if>
}

<#list schema.fieldObjectList as field>
/**

  • Get ${field.baseName?uncap_first}
  • @return ${field.baseName?uncap_first}
    */
    @Schema(name = "${field.baseName?uncap_first}", required = <#if field.required?has_content && field.required == true>true<#else>false</#if>)
    <#if field.dataType?has_content && field.dataTypeSimple == "array">
    public List<<#if field.parentPackage??>${packageModel}.${field.parentPackage}.</#if>${field.dataType}> get${field.baseName?cap_first}() {
    return ${field.baseName?uncap_first};
    }
    <#if field.required == false>

</#if>
<#elseif field.dataType?has_content && field.dataTypeSimple == "map">
public Map<String, ${field.dataType}> get${field.baseName?cap_first}() {
return ${field.baseName?uncap_first};
}
<#if field.required == false>

</#if>
<#elseif field.dataType?has_content && field.dataTypeSimple == "enum">
public ${field.baseName?cap_first} get${field.baseName?cap_first}() {
return ${field.baseName?uncap_first};
}
<#if field.required == false>

</#if>
<#elseif field.dataTypeSimple?has_content>
<#if field.parentPackage??>
public ${packageModel}.${field.parentPackage}.${field.dataTypeSimple?cap_first} get${field.baseName?cap_first}() {
<#else>
public ${field.dataTypeSimple?cap_first} get${field.baseName?cap_first}() {
</#if>
return ${field.baseName?uncap_first};
}
</#if>
</#list>
@OverRide
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
${schema.className} ${schema.className?uncap_first} = (${schema.className}) o;
return <#compress><#list schema.fieldObjectList as field> Objects.equals(this.${field.baseName?uncap_first}, ${schema.className?uncap_first}.${field.baseName?uncap_first})<#if field?has_next> && </#if></#list>;</#compress>
}

@OverRide
public int hashCode() {
return Objects.hash(<#list schema.fieldObjectList as field>${field.baseName?uncap_first}<#if field?has_next>, </#if></#list>);
}

@OverRide
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("${schema.className}{");
<#list schema.fieldObjectList as field>
<#if field_has_next>
sb.append(" ${field.baseName?uncap_first}:").append(${field.baseName?uncap_first}).append(",");
<#else>
sb.append(" ${field.baseName?uncap_first}:").append(${field.baseName?uncap_first});
</#if>
</#list>
sb.append("}");
return sb.toString();
}

<#if schema.schemaCombinator == "anyOf" || schema.schemaCombinator == "oneOf">
private void validatePartialCombinations() {
boolean satisfiedCondition = false;

<#list schema.fieldObjectList as field>
<#if field == schema.fieldObjectList?first>
if (Objects.nonNull(this.${field.baseName?uncap_first})) {
<#else> else if (Objects.nonNull(this.${field.baseName?uncap_first})) {
</#if>
satisfiedCondition = true;
}</#list>

if (!satisfiedCondition) {
  throw new ModelClassException("${schema.className}");
}

}
</#if>

<#list schema.fieldObjectList as field>
<#if field.required>
private void validateRequiredAttributes() {
boolean satisfiedCondition = true;

<#list schema.fieldObjectList?filter(f -> f.required) as field>
<#if field?index == 0>
if (!Objects.nonNull(this.${field.baseName?uncap_first})) {
<#else>
else if (!Objects.nonNull(this.${field.baseName?uncap_first})) {
</#if>
satisfiedCondition = false;
}</#list>

if (!satisfiedCondition) {
  throw new ModelClassException("${schema.className}");
}

}
<#break>
</#if>
</#list>

}

@jemacineiras
Copy link
Contributor

Hi @jgonzalezlawyer,

Thanks for the proposal, it is something we are considering to implement when we complete a refactor to have one Class Generator for all systems. If you want to collaborate, please create a Fork and a Pull Request, and we can work with it.
Cheers

@jemacineiras jemacineiras self-assigned this Aug 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

When branches are created from issues, their pull requests are automatically linked.

2 participants