![JAR search and dependency download from the Maven repository](/logo.png)
com.phoenixnap.oss.ramlapisync.pojo.PojoBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of springmvc-raml-parser Show documentation
Show all versions of springmvc-raml-parser Show documentation
Components including the parsing of RAML documents and Spring MVC Annotations to create RAML models
The newest version!
/*
* Copyright 2002-2017 the original author or authors.
*
* 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 com.phoenixnap.oss.ramlapisync.pojo;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.validation.constraints.Pattern;
import org.apache.commons.collections.MapUtils;
import org.raml.v2.api.model.v10.datamodel.DateTimeTypeDeclaration;
import org.raml.v2.api.model.v10.datamodel.TypeDeclaration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.phoenixnap.oss.ramlapisync.generation.CodeModelHelper;
import com.phoenixnap.oss.ramlapisync.naming.NamingHelper;
import com.phoenixnap.oss.ramlapisync.naming.RamlTypeHelper;
import com.sun.codemodel.ClassType;
import com.sun.codemodel.JAnnotationUse;
import com.sun.codemodel.JBlock;
import com.sun.codemodel.JClass;
import com.sun.codemodel.JClassAlreadyExistsException;
import com.sun.codemodel.JCodeModel;
import com.sun.codemodel.JDefinedClass;
import com.sun.codemodel.JExpr;
import com.sun.codemodel.JExpression;
import com.sun.codemodel.JFieldVar;
import com.sun.codemodel.JInvocation;
import com.sun.codemodel.JMethod;
import com.sun.codemodel.JMod;
import com.sun.codemodel.JVar;
/**
* Builder pattern for POJO generation using jCodeModel. Provides basic utility methods including extension and
* getter/setter generation
*
* @author kurtpa
* @since 0.10.0
*
*/
public class PojoBuilder extends AbstractBuilder {
protected static final Logger logger = LoggerFactory.getLogger(PojoBuilder.class);
public PojoBuilder() {
super();
}
/**
* Constructor allowing chaining of JCodeModels
*
* @param config The Configuration object which controls generation
* @param pojoModel Existing Codemodel to append to
* @param className Class to be created
*
*/
public PojoBuilder(PojoGenerationConfig config, JCodeModel pojoModel, String className) {
super(config, pojoModel);
withName(config.getPojoPackage(), className);
}
public PojoBuilder extendsClass(String className) {
pojoCreationCheck();
if (this.pojo.name().equals(className)) {
throw new IllegalStateException("A class cannot extend itself");
}
this.pojo._extends(CodeModelHelper.findFirstClassBySimpleName(pojoModel, className));
return this;
}
public PojoBuilder extendsClass(PojoBuilder classBuilder) {
if (classBuilder.pojo == null) {
throw new IllegalStateException("Supplied builder does not contain a class");
}
return extendsClass(classBuilder.pojo.name());
}
/**
* Sets this Pojo's name
*
* @param pojoPackage The Package used to create POJO
* @param className Class to be created
* @return This instance
*/
public PojoBuilder withName(String pojoPackage, String className) {
if(!NamingHelper.isValidJavaClassName(className)) {
className = NamingHelper.cleanNameForJava(className);
}
final String fullyQualifiedClassName = pojoPackage + "." + className;
// Initiate package if necessary
if (this.pojoPackage == null) {
withPackage(pojoPackage);
}
// Builders should only have 1 active pojo under their responsibility
if (this.pojo != null) {
throw new IllegalStateException("Class already created");
}
try {
// create the class
logger.debug("Creating class " + fullyQualifiedClassName);
this.pojo = this.pojoModel._class(fullyQualifiedClassName);
// Always add default constructor
withDefaultConstructor(className);
// Handle Serialization
implementsSerializable();
// Add to shortcuts
this.codeModels.put(fullyQualifiedClassName, this.pojo);
} catch (JClassAlreadyExistsException e) {
// class already exists - reuse it!
logger.debug("Enum {} already exists. Reusing it!", fullyQualifiedClassName);
this.pojo = this.pojoModel._getClass(fullyQualifiedClassName);
}
return this;
}
private void withDefaultConstructor(String className) {
// Create default constructor
JMethod constructor = this.pojo.constructor(JMod.PUBLIC);
constructor.javadoc().add("Creates a new " + className + ".");
JBlock defaultConstructorBody = constructor.body();
defaultConstructorBody.invoke("super");
}
private boolean parentContainsField(JClass pojo, String name) {
if (pojo != null && !pojo.fullName().equals(Object.class.getName())) {
JClass parent = pojo._extends();
if (parent != null) {
//Our parent has a parent, lets check if it has it
if (parentContainsField(parent, name)) {
return true;
} else {
if (parent instanceof JDefinedClass) {
return ((JDefinedClass)parent).fields().containsKey(name);
}
}
}
}
return false;
}
public PojoBuilder withField(String name, String type, String comment, RamlTypeValidations validations, TypeDeclaration typeDeclaration) {
pojoCreationCheck();
logger.debug("Adding field: " + name + " to " + this.pojo.name());
JClass resolvedType = resolveType(type);
try {
//If this class is a collection (List)- lets add an import
if (resolvedType.fullName().startsWith(List.class.getName() +"<")) {
resolvedType = this.pojo.owner().ref(List.class).narrow(resolvedType.getTypeParameters().get(0));
}
//If this class is a collection (Set) - lets add an import
if (resolvedType.fullName().startsWith(Set.class.getName() +"<")) {
resolvedType = this.pojo.owner().ref(Set.class).narrow(resolvedType.getTypeParameters().get(0));
}
} catch (Exception ex) {
//skip import
}
//lets ignore this if parent contains it and we will use parent's in the constructor
if (parentContainsField(this.pojo, name)) {
return this;
}
JExpression jExpression = null;
if (StringUtils.hasText(typeDeclaration.defaultValue())) {
if (resolvedType.name().equals(Integer.class.getSimpleName())) {
jExpression = JExpr.lit(Integer.valueOf(typeDeclaration.defaultValue()));
} else if (resolvedType.name().equals(Boolean.class.getSimpleName())) {
jExpression = JExpr.lit(Boolean.valueOf(typeDeclaration.defaultValue()));
} else if (resolvedType.name().equals(Double.class.getSimpleName())) {
jExpression = JExpr.lit(Double.valueOf(typeDeclaration.defaultValue()));
} else if (resolvedType.name().equals(Float.class.getSimpleName())) {
jExpression = JExpr.lit(Float.valueOf(typeDeclaration.defaultValue()));
} else if (resolvedType.name().equals(Long.class.getSimpleName())) {
jExpression = JExpr.lit(Long.valueOf(typeDeclaration.defaultValue()));
} else if (resolvedType.name().equals(BigDecimal.class.getSimpleName())) {
jExpression = JExpr.direct("new BigDecimal(\"" + typeDeclaration.defaultValue() + "\")");
} else if (resolvedType.name().equals(String.class.getSimpleName())) {
jExpression = JExpr.lit(typeDeclaration.defaultValue());
} else if (type.contains(".") && resolvedType instanceof JDefinedClass
&& ((JDefinedClass) resolvedType).getClassType().equals(ClassType.ENUM)) {
jExpression = JExpr.direct(resolvedType.name() + "." + NamingHelper.cleanNameForJavaEnum(typeDeclaration.defaultValue()));
}
} else if(resolvedType.fullName().startsWith(List.class.getName() +"<")){
JClass narrowedListClass = this.pojoModel.ref(ArrayList.class).narrow(resolvedType.getTypeParameters().get(0));
jExpression = JExpr._new(narrowedListClass);
}
// Add private variable
JFieldVar field = this.pojo.field(JMod.PRIVATE, resolvedType, toJavaName(name), jExpression);
if (this.config.isGenerateJSR303Annotations() && validations != null) {
// check if field is complex object so we can mark it with @Valid
boolean isPOJO = type.startsWith(this.pojo._package().name() + ".");
if (!isPOJO
&& resolvedType.getClass().getName().equals("com.sun.codemodel.JNarrowedClass")
&& resolvedType.getTypeParameters().size() == 1) {
JClass typeClass = resolvedType.getTypeParameters().get(0);
isPOJO = typeClass.fullName().startsWith(this.pojo._package().name() + ".");
}
validations.annotateFieldJSR303(field, isPOJO);
}
if (resolvedType.name().equals(Date.class.getSimpleName())) {
JAnnotationUse jAnnotationUse = field.annotate(JsonFormat.class);
String format = null;
if(typeDeclaration instanceof DateTimeTypeDeclaration) {
format = ((DateTimeTypeDeclaration) typeDeclaration).format();
}
RamlTypeHelper.annotateDateWithPattern(jAnnotationUse, typeDeclaration.type(), format);
}
if (StringUtils.hasText(comment)) {
field.javadoc().add(comment);
}
String fieldName = NamingHelper.convertToClassName(name);
// Add get method
JMethod getter = this.pojo.method(JMod.PUBLIC, field.type(), "get" + fieldName);
getter.body()._return(field);
getter.javadoc().add("Returns the " + name + ".");
getter.javadoc().addReturn().add(field.name());
// Add set method
JMethod setter = this.pojo.method(JMod.PUBLIC, this.pojoModel.VOID, "set" + fieldName);
setter.param(field.type(), field.name());
setter.body().assign(JExpr._this().ref(field.name()), JExpr.ref(field.name()));
setter.javadoc().add("Set the " + name + ".");
setter.javadoc().addParam(field.name()).add("the new " + field.name());
// Add with method
if (this.config.isGenerateBuilderMethods()) {
JMethod wither = this.pojo.method(JMod.PUBLIC, this.pojo, "with" + fieldName);
wither.param(field.type(), field.name());
wither.body().assign(JExpr._this().ref(field.name()), JExpr.ref(field.name()))._return(JExpr._this());
wither.javadoc().add("With the " + name + ".");
wither.javadoc().addParam(field.name()).add("the new " + field.name());
}
return this;
}
/**
* Adds a constructor with all the fields in the POJO. If no fields are
* present it will not create an empty constructor because default
* constructor (without fields) is already present.
*
* @return This builder instance
*/
public PojoBuilder withCompleteConstructor() {
pojoCreationCheck();
// first we need to check if there are any fields to add to constructor
// because default constructor (without fields) is already present
Map nonTransientAndNonStaticFields = getNonTransientAndNonStaticFields();
if (MapUtils.isNotEmpty(nonTransientAndNonStaticFields)) {
// Create complete constructor
JMethod constructor = this.pojo.constructor(JMod.PUBLIC);
Map superParametersToAdd = getSuperParametersToAdd(this.pojo);
addSuperConstructorInvocation(constructor, superParametersToAdd);
constructor.javadoc().add("Creates a new " + this.pojo.name() + ".");
Iterator> iterator = nonTransientAndNonStaticFields.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry pair = iterator.next();
constructor.param(pair.getValue().type(), pair.getKey());
constructor.body().assign(JExpr._this().ref(pair.getKey()), JExpr.ref(pair.getKey()));
}
}
return this;
}
private void addSuperConstructorInvocation(JMethod constructor, Map superParametersToAdd) {
JBlock constructorBody = constructor.body();
JInvocation invocation = constructorBody.invoke("super");
for (JVar arg : superParametersToAdd.values()) {
JVar param = constructor.param(arg.type(), arg.name());
invocation.arg(param);
}
}
private Map getSuperParametersToAdd(JClass pojo) {
Map tFields = new LinkedHashMap<>();
JClass parent = pojo._extends();
if (!parent.name().equals(Object.class.getSimpleName())) {
parent = CodeModelHelper.findFirstClassBySimpleName(this.pojoModel, parent.name());
if (parent instanceof JDefinedClass) {
JDefinedClass jParent = (JDefinedClass) parent;
JMethod constructor = null;
Iterator constructors = jParent.constructors();
while (constructors.hasNext()) {
JMethod targetConstructor = constructors.next();
if (constructor == null || constructor.params().size() < targetConstructor.params().size()) {
constructor = targetConstructor;
}
}
for (JVar var : constructor.params()) {
tFields.put(var.name(), var);
}
}
}
return tFields;
}
private Map getNonTransientAndNonStaticFields() {
Map nonStaticNonTransientFields = new LinkedHashMap<>();
if (pojo instanceof JDefinedClass) {
Map fields = ((JDefinedClass) pojo).fields();
Iterator> iterator = fields.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry pair = iterator.next();
// If a field is not static or transient
if ((pair.getValue().mods().getValue() & (JMod.STATIC | JMod.TRANSIENT)) == 0) {
nonStaticNonTransientFields.put(pair.getKey(), pair.getValue());
}
}
}
return nonStaticNonTransientFields;
}
/**
* Generates implementations for hashCode(), equals() and toString() methods if the plugin has been configured to do so.
*/
public void withOverridenMethods() {
if (config.isGenerateHashcodeEqualsToString()) {
withHashCode();
withEquals();
withToString();
}
}
private void withToString() {
pojoCreationCheck();
JMethod toString = this.pojo.method(JMod.PUBLIC, String.class, "toString");
Class> toStringBuilderClass = org.apache.commons.lang3.builder.ToStringBuilder.class;
if (!config.isUseCommonsLang3()) {
toStringBuilderClass = org.apache.commons.lang.builder.ToStringBuilder.class;
}
JClass toStringBuilderRef = this.pojo.owner().ref(toStringBuilderClass);
JInvocation toStringBuilderInvocation = appendFieldsToString(getNonTransientAndNonStaticFields(), toStringBuilderRef);
toString.body()._return(toStringBuilderInvocation.invoke("toString"));
}
private JInvocation appendFieldsToString(Map nonTransientAndNonStaticFields, JClass toStringBuilderRef) {
JInvocation invocation = JExpr._new(toStringBuilderRef).arg(JExpr._this());
Iterator> iterator = nonTransientAndNonStaticFields.entrySet().iterator();
if (!this.pojo._extends().name().equals(Object.class.getSimpleName())) { // If this POJO has a superclass, append the superclass toString() method.
invocation = invocation.invoke("appendSuper").arg(JExpr._super().invoke("toString"));
}
while (iterator.hasNext()) {
Map.Entry pair = iterator.next();
invocation = invocation.invoke("append").arg(JExpr.lit(pair.getKey())).arg(pair.getValue());
}
return invocation;
}
//Ada
private void withHashCode() {
JMethod hashCode = this.pojo.method(JMod.PUBLIC, int.class, "hashCode");
Class> hashCodeBuilderClass = org.apache.commons.lang3.builder.HashCodeBuilder.class;
if (!config.isUseCommonsLang3()) {
hashCodeBuilderClass = org.apache.commons.lang.builder.HashCodeBuilder.class;
}
JClass hashCodeBuilderRef = this.pojo.owner().ref(hashCodeBuilderClass);
JInvocation hashCodeBuilderInvocation = appendFieldsToHashCode(getNonTransientAndNonStaticFields(), hashCodeBuilderRef);
hashCode.body()._return(hashCodeBuilderInvocation.invoke("toHashCode"));
}
private JInvocation appendFieldsToHashCode(Map nonTransientAndNonStaticFields, JClass hashCodeBuilderRef) {
JInvocation invocation = JExpr._new(hashCodeBuilderRef);
Iterator> iterator = nonTransientAndNonStaticFields.entrySet().iterator();
if (!this.pojo._extends().name().equals(Object.class.getSimpleName())) { // If this POJO has a superclass, append the superclass hashCode() method.
invocation = invocation.invoke("appendSuper").arg(JExpr._super().invoke("hashCode"));
}
while (iterator.hasNext()) {
Map.Entry pair = iterator.next();
invocation = invocation.invoke("append").arg(pair.getValue());
}
return invocation;
}
private void withEquals() {
JMethod equals = this.pojo.method(JMod.PUBLIC, boolean.class, "equals");
JVar otherObject = equals.param(Object.class, "other");
Class> equalsBuilderClass = org.apache.commons.lang3.builder.EqualsBuilder.class;
if (!config.isUseCommonsLang3()) {
equalsBuilderClass = org.apache.commons.lang.builder.EqualsBuilder.class;
}
JBlock body = equals.body();
body._if(otherObject.eq(JExpr._null()))._then()._return(JExpr.FALSE);
body._if(otherObject.eq(JExpr._this()))._then()._return(JExpr.TRUE);
body._if(JExpr._this().invoke("getClass").ne(otherObject.invoke("getClass")))._then()._return(JExpr.FALSE);
JVar otherObjectVar = body.decl(this.pojo, "otherObject").init(JExpr.cast(this.pojo, otherObject));
JClass equalsBuilderRef = this.pojo.owner().ref(equalsBuilderClass);
JInvocation equalsBuilderInvocation = appendFieldsToEquals(getNonTransientAndNonStaticFields(), otherObjectVar, equalsBuilderRef);
body._return(equalsBuilderInvocation.invoke("isEquals"));
}
private JInvocation appendFieldsToEquals(Map nonTransientAndNonStaticFields, JVar otherObject, JClass equalsBuilderRef) {
JInvocation invocation = JExpr._new(equalsBuilderRef);
Iterator> iterator = nonTransientAndNonStaticFields.entrySet().iterator();
if (!this.pojo._extends().name().equals(Object.class.getSimpleName())) {// If this POJO has a superclass, append the superclass equals() method.
invocation = invocation.invoke("appendSuper").arg(JExpr._super().invoke("equals").arg(otherObject));
}
while (iterator.hasNext()) {
Map.Entry pair = iterator.next();
invocation = invocation.invoke("append").arg(pair.getValue()).arg(otherObject.ref(pair.getKey()));
}
return invocation;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy