diff --git a/cobigen-cli/cli-systemtest/src/test/java/com/devonfw/cobigen/cli/systemtest/AbstractCliTest.java b/cobigen-cli/cli-systemtest/src/test/java/com/devonfw/cobigen/cli/systemtest/AbstractCliTest.java
index c6b69bb1d5..7dacb804b1 100644
--- a/cobigen-cli/cli-systemtest/src/test/java/com/devonfw/cobigen/cli/systemtest/AbstractCliTest.java
+++ b/cobigen-cli/cli-systemtest/src/test/java/com/devonfw/cobigen/cli/systemtest/AbstractCliTest.java
@@ -98,13 +98,13 @@ public static void determineDevTemplatesPath() throws URISyntaxException, IOExce
}
}
- if (path.getFileName().toString().equals("templates-devon4j-utils")) {
- if (Files.exists(path.resolve("pom.xml"))) {
- try {
- Files.delete(path.resolve("pom.xml"));
- } catch (IOException e) {
- throw new IOException("Error deleting file " + path.resolve("pom.xml"), e);
- }
+ // Replace the pom.xml in the template sets. Needed so that the project in the temp directory is build
+ // properly
+ if (Files.exists(path.resolve("pom.xml"))) {
+ try {
+ Files.delete(path.resolve("pom.xml"));
+ } catch (IOException e) {
+ throw new IOException("Error deleting file " + path.resolve("pom.xml"), e);
}
try {
Files.copy(utilsPom, path.resolve("pom.xml"));
diff --git a/cobigen-templates/crud-angular-client-app/pom.xml b/cobigen-templates/crud-angular-client-app/pom.xml
index c43279405c..e02d94378d 100644
--- a/cobigen-templates/crud-angular-client-app/pom.xml
+++ b/cobigen-templates/crud-angular-client-app/pom.xml
@@ -10,4 +10,11 @@
${revision}
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
\ No newline at end of file
diff --git a/cobigen-templates/crud-angular-client-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java b/cobigen-templates/crud-angular-client-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java
new file mode 100644
index 0000000000..ced2f5fde2
--- /dev/null
+++ b/cobigen-templates/crud-angular-client-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java
@@ -0,0 +1,464 @@
+package com.devonfw.cobigen.templates.devon4j.utils;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.commons.lang3.ClassUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Provides type operations, mainly checks and casts for Java Primitives, to be used in the templates
+ *
+ */
+public class JavaUtil {
+
+ /**
+ * Logger for this class
+ */
+ private static final Logger LOG = LoggerFactory.getLogger(JavaUtil.class);
+
+ /**
+ * The constructor.
+ */
+ public JavaUtil() {
+
+ // Empty for CobiGen to automatically instantiate it
+ }
+
+ /**
+ * Returns the Object version of a Java primitive or the input if the input isn't a java primitive
+ *
+ * @param simpleType String
+ * @return the corresponding object wrapper type simple name of the input if the input is the name of a primitive java
+ * type. The input itself if not. (e.g. "int" results in "Integer")
+ * @throws ClassNotFoundException should not occur.
+ */
+ public String boxJavaPrimitives(String simpleType) throws ClassNotFoundException {
+
+ if (equalsJavaPrimitive(simpleType)) {
+ return ClassUtils.primitiveToWrapper(ClassUtils.getClass(simpleType)).getSimpleName();
+ } else {
+ return simpleType;
+ }
+
+ }
+
+ /**
+ * Returns the simple name of the type of a field in the pojoClass. If the type is a java primitive the name of the
+ * wrapper class is returned
+ *
+ * @param pojoClass {@link Class} the class object of the pojo
+ * @param fieldName {@link String} the name of the field
+ * @return String. The simple name of the field's type. The simple name of the wrapper class in case of java
+ * primitives
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public String boxJavaPrimitives(Class> pojoClass, String fieldName) throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+
+ if (equalsJavaPrimitive(pojoClass, fieldName)) {
+ return ClassUtils.primitiveToWrapper(pojoClass.getDeclaredField(fieldName).getType()).getSimpleName();
+ } else {
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ throw new IllegalAccessError("Could not find field " + fieldName + " in class " + pojoClass);
+ } else {
+ return field.getType().getSimpleName();
+ }
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive
+ *
+ * @param simpleType the type to be checked
+ * @return true iff simpleType is a Java primitive
+ */
+ public boolean equalsJavaPrimitive(String simpleType) {
+
+ try {
+ return ClassUtils.getClass(simpleType).isPrimitive();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive or wrapper
+ *
+ * @param simpleType the type to be checked
+ * @return true iff simpleType is a Java primitive or wrapper
+ */
+ public boolean equalsJavaPrimitiveOrWrapper(String simpleType) {
+
+ try {
+ return ClassUtils.isPrimitiveOrWrapper(ClassUtils.getClass(simpleType));
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the type of the field in the pojo's class is a java primitive
+ *
+ * @param pojoClass the {@link Class} object of the pojo
+ * @param fieldName the name of the field to be checked
+ * @return true iff the field is a java primitive
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean equalsJavaPrimitive(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ return false;
+ }
+
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ return false;
+ } else {
+ return field.getType().isPrimitive();
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive or a Java primitive array
+ *
+ * @param simpleType the Type name to be checked
+ * @return true iff {@link #equalsJavaPrimitive(String)} is true or if simpleType is an array with a primitive
+ * component
+ */
+ public boolean equalsJavaPrimitiveIncludingArrays(String simpleType) {
+
+ Class> klasse;
+
+ try {
+ klasse = ClassUtils.getClass(simpleType).getComponentType();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ return equalsJavaPrimitive(simpleType) || (klasse != null && klasse.isPrimitive());
+ }
+
+ /**
+ * Checks if the given field in the pojo class is a java primitive or an array of java primitives
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldName the name of the field to be checked
+ * @return true iff {@link #equalsJavaPrimitive(Class, String)} is true or the field is an array of primitives
+ * @throws NoSuchFieldException indicating something awfully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean equalsJavaPrimitiveIncludingArrays(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ return equalsJavaPrimitive(pojoClass, fieldName) || (pojoClass.getDeclaredField(fieldName).getType().isArray()
+ && pojoClass.getDeclaredField(fieldName).getType().getComponentType().isPrimitive());
+ }
+
+ /**
+ * Returns a cast statement for a given (java primitive, variable name) pair or nothing if the type isn't a java
+ * primitive
+ *
+ * @param simpleType Java Type
+ * @param varName Variable name
+ * @return String either of the form '((Java Primitive Object Type)varName)' if simpleType is a primitive or the empty
+ * String otherwise
+ * @throws ClassNotFoundException should not occur
+ */
+ public String castJavaPrimitives(String simpleType, String varName) throws ClassNotFoundException {
+
+ if (equalsJavaPrimitive(simpleType)) {
+ return String.format("((%1$s)%2$s)", boxJavaPrimitives(simpleType), varName);
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * Returns a cast statement for a given (java primitive, variable name) pair or nothing if the type isn't a java
+ * primitive
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldName the name of the field to be casted
+ * @return if fieldName points to a primitive field then a casted statement (e.g. for an int field:
+ * '((Integer)field)') or an empty String otherwise
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public String castJavaPrimitives(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ if (equalsJavaPrimitive(pojoClass, fieldName)) {
+ return String.format("((%1$s)%2$s)", boxJavaPrimitives(pojoClass, fieldName), fieldName);
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * @param pojoClass {@link Class} the class object of the pojo
+ * @param fieldName {@link String} the name of the field
+ * @return true if the field is an instance of java.utils.Collections
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean isCollection(Class> pojoClass, String fieldName) throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ return false;
+ }
+
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ return false;
+ } else {
+ return Collection.class.isAssignableFrom(field.getType());
+ }
+
+ }
+
+ /**
+ * Returns the Ext Type to a given java type
+ *
+ * @param simpleType any java type's simple name
+ * @return corresponding Ext type
+ */
+ public String getExtType(String simpleType) {
+
+ switch (simpleType) {
+ case "short":
+ case "Short":
+ case "int":
+ case "Integer":
+ case "long":
+ case "Long":
+ return "Integer";
+ case "float":
+ case "Float":
+ case "double":
+ case "Double":
+ return "Number";
+ case "boolean":
+ case "Boolean":
+ return "Boolean";
+ case "char":
+ case "Character":
+ case "String":
+ return "String";
+ case "Date":
+ return "Date";
+ default:
+ return "Field";
+ }
+ }
+
+ /**
+ * returns the Angular5 type associated with a Java primitive
+ *
+ * @param simpleType :{@link String} the type to be parsed
+ * @return the corresponding Angular type or 'any' otherwise
+ */
+ public String getAngularType(String simpleType) {
+
+ switch (simpleType) {
+ case "boolean":
+ return "boolean";
+ case "Boolean":
+ return "boolean";
+ case "short":
+ return "number";
+ case "Short":
+ return "number";
+ case "int":
+ return "number";
+ case "Integer":
+ return "number";
+ case "long":
+ return "number";
+ case "Long":
+ return "number";
+ case "float":
+ return "number";
+ case "Float":
+ return "number";
+ case "double":
+ return "number";
+ case "Double":
+ return "number";
+ case "char":
+ return "string";
+ case "Character":
+ return "string";
+ case "String":
+ return "string";
+ case "byte":
+ return "number";
+ default:
+ return "any";
+ }
+ }
+
+ /**
+ * returns the class name of the return type of a specific method.
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName {@link String} the name of the method
+ * @return the class name of the return type of the specified method
+ * @throws SecurityException If no method of the given name can be found
+ * @throws NoSuchMethodException If no method of the given name can be found
+ */
+ public String getReturnType(Class> pojoClass, String methodName) throws NoSuchMethodException, SecurityException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+ String s = "-";
+ Method method = findMethod(pojoClass, methodName);
+ if (method != null && !method.getReturnType().equals(Void.TYPE)) {
+ s = method.getReturnType().toString();
+ s = s.substring(s.lastIndexOf('.') + 1, s.length());
+ }
+ return s;
+ }
+
+ /**
+ *
+ * This methods returns the return type of the method in the given pojoClass which are annotated with the parameter
+ * annotatedClass
+ *
+ * @param pojoClass - The class in which to find if it has methods with annotatedClass
+ * @param annotatedClassName - The annotation which needs to be found
+ * @return Return type of the method annotated with the given annotation, else "null"
+ * @throws ClassNotFoundException if the annotated class name could not be found in the class path
+ */
+ @SuppressWarnings("unchecked")
+ public String getReturnTypeOfMethodAnnotatedWith(Class> pojoClass, String annotatedClassName)
+ throws ClassNotFoundException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+
+ Method[] methods = pojoClass.getDeclaredMethods();
+ for (Method method : methods) {
+ if (!method.getName().startsWith("get")) {
+ continue;
+ }
+ for (Annotation a : method.getAnnotations()) {
+ // better if (method.isAnnotationPresent(classObj)) {, but postponed as of different class
+ // loaders of a.getClass() and pojoClass.getClass()
+ if (a.getClass().getCanonicalName().equals(annotatedClassName)) {
+ return method.getReturnType().getSimpleName();
+ }
+ }
+ }
+ return "null";
+ }
+
+ /**
+ * returns the HTTP request type corresponding to an annotation type
+ *
+ * @param annotations The annotation to get the type name of
+ * @return the HTTP request type name of the selected annotation
+ */
+ public String getRequestType(Map annotations) {
+
+ if (annotations.containsKey("javax_ws_rs_GET")) {
+ return "GET";
+ } else if (annotations.containsKey("javax_ws_rs_PUT")) {
+ return "PUT";
+ } else if (annotations.containsKey("javax_ws_rs_POST")) {
+ return "POST";
+ } else if (annotations.containsKey("javax_ws_rs_DELETE")) {
+ return "DELETE";
+ } else if (annotations.containsKey("javax_ws_rs_PATCH")) {
+ return "PATCH";
+ } else {
+ return "-";
+ }
+ }
+
+ /**
+ * Helper method to find a class's specific method
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName The name of the method to be found
+ * @return The method object of the method to be found, null if it wasn't found
+ */
+ private Method findMethod(Class> pojoClass, String methodName) {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+ for (Method m : pojoClass.getMethods()) {
+ if (m.getName().equals(methodName)) {
+ return m;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Checks whether the class given by the full qualified name is an enum
+ *
+ * @param className full qualified class name
+ * @return true
if the class is an enum, false
otherwise
+ */
+ public boolean isEnum(String className) {
+
+ try {
+ return ClassUtils.getClass(className).isEnum();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), className);
+ return false;
+ }
+ }
+
+ /**
+ * Returns the first enum value of an enum class
+ *
+ * @param className full qualified class name
+ * @return the first enum value name found in order
+ */
+ public String getFirstEnumValue(String className) {
+
+ try {
+ Class> enumClass = ClassUtils.getClass(className);
+ Field[] declaredFields = enumClass.getDeclaredFields();
+ if (declaredFields.length > 0) {
+ return declaredFields[0].getName();
+ } else {
+ return null;
+ }
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), className);
+ return null;
+ }
+ }
+}
diff --git a/cobigen-templates/crud-ionic-client-app/pom.xml b/cobigen-templates/crud-ionic-client-app/pom.xml
index e4ce241379..3a42d2a3e1 100644
--- a/cobigen-templates/crud-ionic-client-app/pom.xml
+++ b/cobigen-templates/crud-ionic-client-app/pom.xml
@@ -10,4 +10,11 @@
${revision}
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
\ No newline at end of file
diff --git a/cobigen-templates/crud-ionic-client-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java b/cobigen-templates/crud-ionic-client-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java
new file mode 100644
index 0000000000..2d4025071d
--- /dev/null
+++ b/cobigen-templates/crud-ionic-client-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java
@@ -0,0 +1,464 @@
+package com.devonfw.cobigen.templates.devon4j.utils;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.commons.lang3.ClassUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Provides type operations, mainly checks and casts for Java Primitives, to be used in the templates
+ *
+ */
+public class JavaUtil {
+
+ /**
+ * Logger for this class
+ */
+ private static final Logger LOG = LoggerFactory.getLogger(JavaUtil.class);
+
+ /**
+ * The constructor.
+ */
+ public JavaUtil() {
+
+ // Empty for CobiGen to automatically instantiate it
+ }
+
+ /**
+ * Returns the Object version of a Java primitive or the input if the input isn't a java primitive
+ *
+ * @param simpleType String
+ * @return the corresponding object wrapper type simple name of the input if the input is the name of a primitive java
+ * type. The input itself if not. (e.g. "int" results in "Integer")
+ * @throws ClassNotFoundException should not occur.
+ */
+ public String boxJavaPrimitives(String simpleType) throws ClassNotFoundException {
+
+ if (equalsJavaPrimitive(simpleType)) {
+ return ClassUtils.primitiveToWrapper(ClassUtils.getClass(simpleType)).getSimpleName();
+ } else {
+ return simpleType;
+ }
+
+ }
+
+ /**
+ * Returns the simple name of the type of a field in the pojoClass. If the type is a java primitive the name of the
+ * wrapper class is returned
+ *
+ * @param pojoClass {@link Class} the class object of the pojo
+ * @param fieldName {@link String} the name of the field
+ * @return String. The simple name of the field's type. The simple name of the wrapper class in case of java
+ * primitives
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public String boxJavaPrimitives(Class> pojoClass, String fieldName) throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+
+ if (equalsJavaPrimitive(pojoClass, fieldName)) {
+ return ClassUtils.primitiveToWrapper(pojoClass.getDeclaredField(fieldName).getType()).getSimpleName();
+ } else {
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ throw new IllegalAccessError("Could not find field " + fieldName + " in class " + pojoClass);
+ } else {
+ return field.getType().getSimpleName();
+ }
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive
+ *
+ * @param simpleType the type to be checked
+ * @return true iff simpleType is a Java primitive
+ */
+ public boolean equalsJavaPrimitive(String simpleType) {
+
+ try {
+ return ClassUtils.getClass(simpleType).isPrimitive();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive or wrapper
+ *
+ * @param simpleType the type to be checked
+ * @return true iff simpleType is a Java primitive or wrapper
+ */
+ public boolean equalsJavaPrimitiveOrWrapper(String simpleType) {
+
+ try {
+ return ClassUtils.isPrimitiveOrWrapper(ClassUtils.getClass(simpleType));
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the type of the field in the pojo's class is a java primitive
+ *
+ * @param pojoClass the {@link Class} object of the pojo
+ * @param fieldName the name of the field to be checked
+ * @return true iff the field is a java primitive
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean equalsJavaPrimitive(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ return false;
+ }
+
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ return false;
+ } else {
+ return field.getType().isPrimitive();
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive or a Java primitive array
+ *
+ * @param simpleType the Type name to be checked
+ * @return true iff {@link #equalsJavaPrimitive(String)} is true or if simpleType is an array with a primitive
+ * component
+ */
+ public boolean equalsJavaPrimitiveIncludingArrays(String simpleType) {
+
+ Class> klasse;
+
+ try {
+ klasse = ClassUtils.getClass(simpleType).getComponentType();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ return equalsJavaPrimitive(simpleType) || (klasse != null && klasse.isPrimitive());
+ }
+
+ /**
+ * Checks if the given field in the pojo class is a java primitive or an array of java primitives
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldName the name of the field to be checked
+ * @return true iff {@link #equalsJavaPrimitive(Class, String)} is true or the field is an array of primitives
+ * @throws NoSuchFieldException indicating something awfully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean equalsJavaPrimitiveIncludingArrays(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ return equalsJavaPrimitive(pojoClass, fieldName) || (pojoClass.getDeclaredField(fieldName).getType().isArray()
+ && pojoClass.getDeclaredField(fieldName).getType().getComponentType().isPrimitive());
+ }
+
+ /**
+ * Returns a cast statement for a given (java primitive, variable name) pair or nothing if the type isn't a java
+ * primitive
+ *
+ * @param simpleType Java Type
+ * @param varName Variable name
+ * @return String either of the form '((Java Primitive Object Type)varName)' if simpleType is a primitive or the empty
+ * String otherwise
+ * @throws ClassNotFoundException should not occur
+ */
+ public String castJavaPrimitives(String simpleType, String varName) throws ClassNotFoundException {
+
+ if (equalsJavaPrimitive(simpleType)) {
+ return String.format("((%1$s)%2$s)", boxJavaPrimitives(simpleType), varName);
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * Returns a cast statement for a given (java primitive, variable name) pair or nothing if the type isn't a java
+ * primitive
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldName the name of the field to be casted
+ * @return if fieldName points to a primitive field then a casted statement (e.g. for an int field:
+ * '((Integer)field)') or an empty String otherwise
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public String castJavaPrimitives(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ if (equalsJavaPrimitive(pojoClass, fieldName)) {
+ return String.format("((%1$s)%2$s)", boxJavaPrimitives(pojoClass, fieldName), fieldName);
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * @param pojoClass {@link Class} the class object of the pojo
+ * @param fieldName {@link String} the name of the field
+ * @return true if the field is an instance of java.utils.Collections
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean isCollection(Class> pojoClass, String fieldName) throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ return false;
+ }
+
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ return false;
+ } else {
+ return Collection.class.isAssignableFrom(field.getType());
+ }
+
+ }
+
+ /**
+ * Returns the Ext Type to a given java type
+ *
+ * @param simpleType any java type's simple name
+ * @return corresponding Ext type
+ */
+ public String getExtType(String simpleType) {
+
+ switch (simpleType) {
+ case "short":
+ case "Short":
+ case "int":
+ case "Integer":
+ case "long":
+ case "Long":
+ return "Integer";
+ case "float":
+ case "Float":
+ case "double":
+ case "Double":
+ return "Number";
+ case "boolean":
+ case "Boolean":
+ return "Boolean";
+ case "char":
+ case "Character":
+ case "String":
+ return "String";
+ case "Date":
+ return "Date";
+ default:
+ return "Field";
+ }
+ }
+
+ /**
+ * returns the Angular5 type associated with a Java primitive
+ *
+ * @param simpleType :{@link String} the type to be parsed
+ * @return the corresponding Angular type or 'any' otherwise
+ */
+ public String getAngularType(String simpleType) {
+
+ switch (simpleType) {
+ case "boolean":
+ return "boolean";
+ case "Boolean":
+ return "boolean";
+ case "short":
+ return "number";
+ case "Short":
+ return "number";
+ case "int":
+ return "number";
+ case "Integer":
+ return "number";
+ case "long":
+ return "number";
+ case "Long":
+ return "number";
+ case "float":
+ return "number";
+ case "Float":
+ return "number";
+ case "double":
+ return "number";
+ case "Double":
+ return "number";
+ case "char":
+ return "string";
+ case "Character":
+ return "string";
+ case "String":
+ return "string";
+ case "byte":
+ return "number";
+ default:
+ return "any";
+ }
+ }
+
+ /**
+ * returns the class name of the return type of a specific method.
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName {@link String} the name of the method
+ * @return the class name of the return type of the specified method
+ * @throws SecurityException If no method of the given name can be found
+ * @throws NoSuchMethodException If no method of the given name can be found
+ */
+ public String getReturnType(Class> pojoClass, String methodName) throws NoSuchMethodException, SecurityException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+ String s = "-";
+ Method method = findMethod(pojoClass, methodName);
+ if (method != null && !method.getReturnType().equals(Void.TYPE)) {
+ s = method.getReturnType().toString();
+ s = s.substring(s.lastIndexOf('.') + 1, s.length());
+ }
+ return s;
+ }
+
+ /**
+ *
+ * This methods returns the return type of the method in the given pojoClass which are annotated with the parameter
+ * annotatedClass
+ *
+ * @param pojoClass - The class in which to find if it has methods with annotatedClass
+ * @param annotatedClassName - The annotation which needs to be found
+ * @return Return type of the method annotated with the given annotation, else "null"
+ * @throws ClassNotFoundException if the annotated class name could not be found in the class path
+ */
+ @SuppressWarnings("unchecked")
+ public String getReturnTypeOfMethodAnnotatedWith(Class> pojoClass, String annotatedClassName)
+ throws ClassNotFoundException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+
+ Method[] methods = pojoClass.getDeclaredMethods();
+ for (Method method : methods) {
+ if (!method.getName().startsWith("get")) {
+ continue;
+ }
+ for (Annotation a : method.getAnnotations()) {
+ // better if (method.isAnnotationPresent(classObj)) {, but postponed as of different class
+ // loaders of a.getClass() and pojoClass.getClass()
+ if (a.getClass().getCanonicalName().equals(annotatedClassName)) {
+ return method.getReturnType().getSimpleName();
+ }
+ }
+ }
+ return "null";
+ }
+
+ /**
+ * returns the HTTP request type corresponding to an annotation type
+ *
+ * @param annotations The annotation to get the type name of
+ * @return the HTTP request type name of the selected annotation
+ */
+ public String getRequestType(Map annotations) {
+
+ if (annotations.containsKey("javax_ws_rs_GET")) {
+ return "GET";
+ } else if (annotations.containsKey("javax_ws_rs_PUT")) {
+ return "PUT";
+ } else if (annotations.containsKey("javax_ws_rs_POST")) {
+ return "POST";
+ } else if (annotations.containsKey("javax_ws_rs_DELETE")) {
+ return "DELETE";
+ } else if (annotations.containsKey("javax_ws_rs_PATCH")) {
+ return "PATCH";
+ } else {
+ return "-";
+ }
+ }
+
+ /**
+ * Helper method to find a class's specific method
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName The name of the method to be found
+ * @return The method object of the method to be found, null if it wasn't found
+ */
+ private Method findMethod(Class> pojoClass, String methodName) {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+ for (Method m : pojoClass.getMethods()) {
+ if (m.getName().equals(methodName)) {
+ return m;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Checks whether the class given by the full qualified name is an enum
+ *
+ * @param className full qualified class name
+ * @return true
if the class is an enum, false
otherwise
+ */
+ public boolean isEnum(String className) {
+
+ try {
+ return ClassUtils.getClass(className).isEnum();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), className);
+ return false;
+ }
+ }
+
+ /**
+ * Returns the first enum value of an enum class
+ *
+ * @param className full qualified class name
+ * @return the first enum value name found in order
+ */
+ public String getFirstEnumValue(String className) {
+
+ try {
+ Class> enumClass = ClassUtils.getClass(className);
+ Field[] declaredFields = enumClass.getDeclaredFields();
+ if (declaredFields.length > 0) {
+ return declaredFields[0].getName();
+ } else {
+ return null;
+ }
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), className);
+ return null;
+ }
+ }
+}
diff --git a/cobigen-templates/crud-java-ea-uml/pom.xml b/cobigen-templates/crud-java-ea-uml/pom.xml
index 285f86ef71..69799afa8e 100644
--- a/cobigen-templates/crud-java-ea-uml/pom.xml
+++ b/cobigen-templates/crud-java-ea-uml/pom.xml
@@ -10,4 +10,10 @@
${revision}
+
+
+ org.apache.commons
+ commons-lang3
+
+
\ No newline at end of file
diff --git a/cobigen-templates/crud-java-ea-uml/src/main/java/com/devonfw/cobigen/templates/devon4j/constants/Field.java b/cobigen-templates/crud-java-ea-uml/src/main/java/com/devonfw/cobigen/templates/devon4j/constants/Field.java
new file mode 100644
index 0000000000..5376daaea9
--- /dev/null
+++ b/cobigen-templates/crud-java-ea-uml/src/main/java/com/devonfw/cobigen/templates/devon4j/constants/Field.java
@@ -0,0 +1,48 @@
+package com.devonfw.cobigen.templates.devon4j.constants;
+
+/**
+ * Contains the used keys for the pojo field mapping
+ */
+public enum Field {
+
+ /**
+ * Name of the field
+ */
+ NAME("name"),
+ /**
+ * Type of the field
+ */
+ TYPE("type"),
+ /**
+ * Canonical Type of the field
+ */
+ CANONICAL_TYPE("canonicalType"),
+ /**
+ * The Javadoc of the field
+ */
+ JAVA_DOC("javaDoc"),
+ /**
+ * Annotations
+ */
+ ANNOTATIONS("annotations");
+
+ /**
+ * key value
+ */
+ private String value;
+
+ /**
+ * @param value of the key
+ */
+ Field(String value) {
+
+ this.value = value;
+ }
+
+ @Override
+ public String toString() {
+
+ return this.value;
+ }
+
+}
diff --git a/cobigen-templates/crud-java-ea-uml/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/DevonfwUtil.java b/cobigen-templates/crud-java-ea-uml/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/DevonfwUtil.java
new file mode 100644
index 0000000000..36e39b5e06
--- /dev/null
+++ b/cobigen-templates/crud-java-ea-uml/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/DevonfwUtil.java
@@ -0,0 +1,450 @@
+package com.devonfw.cobigen.templates.devon4j.utils;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.NodeList;
+
+import com.devonfw.cobigen.templates.devon4j.constants.Field;
+import com.sun.org.apache.xerces.internal.dom.DeferredElementNSImpl;
+
+/**
+ * A class for shared devon4j specific functions in the templates
+ *
+ */
+@SuppressWarnings("restriction")
+public class DevonfwUtil {
+
+ /**
+ * Check whether the given 'canonicalType' is a devon4j Entity, which is declared in the given 'component'
+ *
+ * @param canonicalType the type name
+ * @param component the component name
+ * @return true iff the canonicalType is a devon Entity
+ */
+ public boolean isEntityInComponent(String canonicalType, String component) {
+
+ return canonicalType.matches(String.format(".+%1$s\\.dataaccess\\.api\\.[A-Za-z0-9]+Entity(<.*)?", component));
+ }
+
+ /**
+ * Check whether the given 'canonicalType' is declared in the given 'component'
+ *
+ * @param canonicalType the type name
+ * @param component the component name
+ * @return true iff the canonicalType is inside the given component
+ */
+ public boolean isTypeInComponent(String canonicalType, String component) {
+
+ return canonicalType.matches(String.format("%1$s.[A-Za-z0-9]+(<.*)?", component));
+ }
+
+ /**
+ * Determines the ID getter for a given 'field' dependent on whether the getter should access the ID via an object
+ * reference or a direct ID getter
+ *
+ * @param field the field
+ * @param byObjectReference boolean
+ * @param component the devon4j component name
+ * @return 'get' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)} + '()' with
+ * capitalize=true
+ */
+ public String resolveIdGetter(Map field, boolean byObjectReference, String component) {
+
+ // If field comes from an UML file
+ if (field.getClass().toGenericString().contains("freemarker.ext.beans.HashAdapter")) {
+ DeferredElementNSImpl umlNode = (DeferredElementNSImpl) field;
+ return resolveIdGetter(umlNode, byObjectReference, component);
+ }
+ return "get" + resolveIdVariableNameOrSetterGetterSuffix(field, byObjectReference, true, component) + "()";
+ }
+
+ /**
+ * Determines the ID getter for a given 'field' dependent on whether the getter should access the ID via an object
+ * reference or a direct ID getter
+ *
+ * This method is used when the field parameter comes from an UML file. The name and type of the attributes must be
+ * pre-processed for later inserting them inside the HashMap.
+ *
+ * @param field the field
+ * @param byObjectReference boolean
+ * @param component the devon4j component name
+ * @return 'get' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)} + '()' with
+ * capitalize=true
+ */
+ public String resolveIdGetter(DeferredElementNSImpl field, boolean byObjectReference, String component) {
+
+ HashMap nodeHash = new HashMap<>();
+
+ // Putting the name of the attribute to the hash
+ nodeHash.put(Field.NAME.toString(), field.getAttribute("name"));
+
+ // Putting the type of the attribute to the hash
+ NodeList childs = field.getChildNodes();
+ for (int i = 0; i < childs.getLength(); i++) {
+ // Retrieve "type" tag
+ if (childs.item(i).getNodeName().equals("type")) {
+ NamedNodeMap attrs = childs.item(i).getAttributes();
+ for (int j = 0; j < attrs.getLength(); j++) {
+ Attr attribute = (Attr) attrs.item(j);
+ // Try to find the attribute that contains the type
+ if (attribute.getName().equals("xmi:idref")) {
+ nodeHash.put(Field.TYPE.toString(), attribute.getName().replace("EAJava_", ""));
+ }
+ }
+ }
+ }
+ return "get" + resolveIdVariableNameOrSetterGetterSuffix(nodeHash, byObjectReference, true, component) + "()";
+
+ }
+
+ /**
+ * Determines the ID getter for a given 'field' dependent on whether the getter should access the ID via an object
+ * reference or a direct ID getter
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldMap the field mapping
+ * @param byObjectReference boolean
+ * @param component the devon4j component name
+ * @return 'get' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)} + '()' with
+ * capitalize=true
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdGetter(Class> pojoClass, Map fieldMap, boolean byObjectReference,
+ String component) throws NoSuchFieldException, SecurityException {
+
+ return "get" + resolveIdVariableNameOrSetterGetterSuffix(pojoClass, fieldMap, byObjectReference, true, component)
+ + "()";
+ }
+
+ /**
+ * same as {@link #resolveIdGetter(Map, boolean, String)} but with byObjectReference=false and component=""
+ *
+ * @param field the field
+ * @return 'get' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map,boolean,boolean,String)} + '()' with
+ * capitalize=true
+ */
+ public String resolveIdGetter(Map field) {
+
+ return this.resolveIdGetter(field, false, "");
+ }
+
+ /**
+ * same as {@link #resolveIdGetter(Class,Map,boolean,String)} but with byObjectReference=false and component=""
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldMap the field mapping
+ * @return 'get' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map,boolean,boolean,String)} + '()' with
+ * capitalize=true
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdGetter(Class> pojoClass, Map fieldMap)
+ throws NoSuchFieldException, SecurityException {
+
+ return resolveIdGetter(pojoClass, fieldMap, false, "");
+ }
+
+ /**
+ * Determines the ID setter for a given 'field' dependent on whether the setter should access the ID via an object
+ * reference or a direct ID setter. In contrast to resolveIdGetter, this function does not generate the function
+ * parenthesis to enable parameter declaration.
+ *
+ * @param field the field
+ * @param byObjectReference boolean
+ * @param component the devon4j component name
+ * @return 'set' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)} with
+ * capitalize=true
+ */
+ public String resolveIdSetter(Map field, boolean byObjectReference, String component) {
+
+ return "set" + resolveIdVariableNameOrSetterGetterSuffix(field, byObjectReference, true, component);
+ }
+
+ /**
+ * same as {@link #resolveIdSetter(Map, boolean, String)} but with byObjectReference=false and component=""
+ *
+ * @param field the field
+ * @return 'set' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)} with
+ * capitalize=true
+ */
+ public String resolveIdSetter(Map field) {
+
+ return this.resolveIdSetter(field, false, "");
+ }
+
+ /**
+ * Determines the ID setter for a given 'field' dependent on whether the setter should access the ID via an object
+ * reference or a direct ID setter. In contrast to resolveIdGetter, this function does not generate the function
+ * parenthesis to enable parameter declaration.
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldMap the field mapping
+ * @param byObjectReference boolean
+ * @param component the devon4j component name
+ * @return 'set'+ {@link #resolveIdVariableNameOrSetterGetterSuffix(Map,boolean,boolean,String)} with capitalize=true
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdSetter(Class> pojoClass, Map fieldMap, boolean byObjectReference,
+ String component) throws NoSuchFieldException, SecurityException {
+
+ return "set" + resolveIdVariableNameOrSetterGetterSuffix(pojoClass, fieldMap, byObjectReference, true, component);
+ }
+
+ /**
+ * same as {@link #resolveIdSetter(Class,Map,boolean,String)} but with byObjectReference=false and component=""
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldMap the field mapping
+ * @return 'set' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map,boolean,boolean,String)} with capitalize=true
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdSetter(Class> pojoClass, Map fieldMap)
+ throws NoSuchFieldException, SecurityException {
+
+ return resolveIdSetter(pojoClass, fieldMap, false, "");
+ }
+
+ /**
+ * Determines the variable name for the id value of the 'field'
+ *
+ * @param field the field
+ * @return {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)}) with
+ * byObjectReference=false, capitalize=false and component=""
+ */
+ public String resolveIdVariableName(Map field) {
+
+ // the component is passed down as an empty string since byObjectReference is false and therefore the
+ // component is
+ // never touched
+ return resolveIdVariableNameOrSetterGetterSuffix(field, false, false, "");
+ }
+
+ /**
+ * Determines the variable name for the id value of the specified field in the pojo
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldMap the field mapping
+ * @return {@link #resolveIdVariableNameOrSetterGetterSuffix(Class, Map, boolean, boolean, String)}) with
+ * byObjectReference=false, capitalize=false and component=""
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdVariableName(Class> pojoClass, Map fieldMap)
+ throws NoSuchFieldException, SecurityException {
+
+ // the component is passed down as an empty string since byObjectReference is false and therefore the
+ // component is
+ // never touched
+ return resolveIdVariableNameOrSetterGetterSuffix(pojoClass, fieldMap, false, false, "");
+ }
+
+ /**
+ * Determines the ID setter/getter suffix for a given 'field' dependent on whether the setter/getter should access the
+ * ID via an object reference or a direct ID setter/getter
+ *
+ * @param field the field
+ * @param byObjectReference boolean
+ * @param capitalize if the field name should be capitalized
+ * @param component the devon4j component. Only needed if $byObjectReference is true
+ * @return idVariable name or getter/setter suffix
+ */
+ public String resolveIdVariableNameOrSetterGetterSuffix(Map field, boolean byObjectReference,
+ boolean capitalize, String component) {
+
+ String fieldName = (String) field.get(Field.NAME.toString());
+ if (capitalize) {
+ fieldName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
+ }
+ String suffix = "";
+
+ String fieldType = (String) field.get(Field.TYPE.toString());
+ String fieldCType = (String) field.get(Field.CANONICAL_TYPE.toString());
+ if (fieldType.contains("Entity")) {
+ if (fieldCType.startsWith("java.util.List") || fieldCType.startsWith("java.util.Set")) {
+ suffix = "Ids";
+ if (fieldName.endsWith("s")) {
+ // Assume trailing 's' as indicator for a plural
+ fieldName = fieldName.substring(0, fieldName.length() - 1);
+ }
+ } else {
+ suffix = "Id";
+ }
+ if (byObjectReference && isTypeInComponent(fieldCType, component)) {
+ // direct references for Entities in same component, so get id of the object reference
+ suffix = "().getId";
+ }
+ }
+
+ return fieldName + suffix;
+
+ }
+
+ /**
+ * Determines the ID setter/getter suffix for a given 'field' dependent on whether the setter/getter should access the
+ * ID via an object reference or a direct ID setter/getter
+ *
+ * @param pojoClass the {@link Class} object of the pojo
+ * @param fieldMap the field mapping
+ * @param byObjectReference boolean
+ * @param capitalize if the field name should be capitalized
+ * @param component the devon4j component. Only needed if byObjectReference is true
+ * @return idVariable name or getter/setter suffix
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdVariableNameOrSetterGetterSuffix(Class> pojoClass, Map fieldMap,
+ boolean byObjectReference, boolean capitalize, String component) throws NoSuchFieldException, SecurityException {
+
+ String resultName = (String) fieldMap.get(Field.NAME.toString());
+ if (capitalize) {
+ resultName = resultName.substring(0, 1).toUpperCase() + resultName.substring(1);
+ }
+ String suffix = "";
+ String fieldType = (String) fieldMap.get(Field.TYPE.toString());
+ String fieldName = (String) fieldMap.get(Field.NAME.toString());
+ if (fieldType.contains("Entity")) {
+ if (Collection.class.isAssignableFrom(pojoClass.getDeclaredField(fieldName).getType())) {
+ suffix = "Ids";
+ if (resultName.endsWith("s")) {
+ // Assume trailing 's' as indicator for a plural
+ resultName = resultName.substring(0, resultName.length() - 1);
+ }
+ } else {
+ suffix = "Id";
+ }
+ if (byObjectReference
+ && isEntityInComponent(pojoClass.getDeclaredField(fieldName).getType().getName(), component)) {
+ // direct references for Entities in same component, so get id of the object reference
+ suffix = "().getId";
+ }
+ }
+
+ return resultName + suffix;
+
+ }
+
+ /**
+ * Returns the argument type of the list or set from a field. If the string contains "Entity" it will remove that
+ * part. For example, if we have a List <SampleEntity> it will return "Sample"
+ *
+ * @param field the field
+ * @param pojoClass the object class of the Entity that contains the field
+ * @return fieldType argument of the list
+ * @throws SecurityException if field type could not accessed
+ * @throws NoSuchFieldException if field could not be found
+ */
+ public String getListArgumentType(Map field, Class> pojoClass)
+ throws NoSuchFieldException, SecurityException {
+
+ JavaUtil javaUtil = new JavaUtil();
+
+ String fieldType = (String) field.get(Field.TYPE.toString());
+ String fieldName = (String) field.get(Field.NAME.toString());
+
+ if (fieldType.contains("Entity")) {
+ if (javaUtil.isCollection(pojoClass, fieldName)) {
+
+ fieldType = fieldType.replace("Entity", "");
+ // Regex: Extracts the argument type of the list 'List' => type
+ String regex = "(?<=\\<).+?(?=\\>)";
+ Pattern pattern = Pattern.compile(regex);
+ Matcher regexMatcher = pattern.matcher(fieldType);
+
+ if (regexMatcher.find()) {
+ fieldType = regexMatcher.group(0);
+ }
+ }
+ }
+ return fieldType;
+
+ }
+
+ /**
+ * Converts all occurrences of devon4j Entity types in the given 'field' simple type (possibly generic) to Longs
+ *
+ * @param field the field
+ * @return the field type as String. If field type contains 'Entity' the result is Long
+ */
+ public String getSimpleEntityTypeAsLongReference(Map field) {
+
+ String fieldType = (String) field.get(Field.TYPE.toString());
+ if (fieldType.endsWith("Entity")) {
+ fieldType = fieldType.replaceAll("[^<>]+Entity", "Long");
+ }
+ return fieldType;
+ }
+
+ /**
+ * If the string last character is an 's', then it gets removed
+ *
+ * @param targetClassName string to remove plural
+ * @return string without 's'
+ */
+ public String removePlural(String targetClassName) {
+
+ if (targetClassName.charAt(targetClassName.length() - 1) == 's') {
+ targetClassName = targetClassName.substring(0, targetClassName.length() - 1);
+ }
+ return targetClassName;
+ }
+
+ /**
+ * Checks whether the operation with the given ID corresponds to any standard CRUD method name.
+ *
+ * @param operationId operation ID interpreted as method name
+ * @param entityName entity name to check standard CRUD methods for
+ * @return true
if the operation ID maps any standard CRUD method name, false
otherwise
+ */
+ public boolean isCrudOperation(String operationId, String entityName) {
+
+ if (operationId == null) {
+ return false;
+ }
+ String opIdLowerCase = operationId.toLowerCase();
+ String entityNameLowerCase = entityName.toLowerCase();
+ if (opIdLowerCase.contains(entityNameLowerCase)) {
+ return opIdLowerCase.equals("find" + entityNameLowerCase)
+ || opIdLowerCase.equals("find" + entityNameLowerCase + "Etos")
+ || opIdLowerCase.equals("delete" + entityNameLowerCase) || opIdLowerCase.equals("save" + entityNameLowerCase);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Converts the given media type to the spring Java enum value
+ *
+ * @param mediaType to be converted
+ * @return the spring enum value representing the given media type
+ */
+ public String getSpringMediaType(String mediaType) {
+
+ switch (mediaType) {
+ case "application/xml":
+ return "APPLICATION_XML_VALUE";
+ case "application / x-www-form-urlencoded":
+ return "APPLICATION_FORM_URLENCODED_VALUE";
+ case "multipart/form-data":
+ return "MULTIPART_FORM_DATA_VALUE";
+ case "text/plain":
+ return "TEXT_PLAIN_VALUE";
+ case "text/html":
+ return "TEXT_HTML_VALUE";
+ case "application/pdf":
+ return "APPLICATION_PDF_VALUE";
+ case "image/png":
+ return "IMAGE_PNG_VALUE";
+ default:
+ return "APPLICATION_JSON_VALUE";
+ }
+ }
+}
\ No newline at end of file
diff --git a/cobigen-templates/crud-java-ea-uml/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java b/cobigen-templates/crud-java-ea-uml/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java
new file mode 100644
index 0000000000..ced2f5fde2
--- /dev/null
+++ b/cobigen-templates/crud-java-ea-uml/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java
@@ -0,0 +1,464 @@
+package com.devonfw.cobigen.templates.devon4j.utils;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.commons.lang3.ClassUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Provides type operations, mainly checks and casts for Java Primitives, to be used in the templates
+ *
+ */
+public class JavaUtil {
+
+ /**
+ * Logger for this class
+ */
+ private static final Logger LOG = LoggerFactory.getLogger(JavaUtil.class);
+
+ /**
+ * The constructor.
+ */
+ public JavaUtil() {
+
+ // Empty for CobiGen to automatically instantiate it
+ }
+
+ /**
+ * Returns the Object version of a Java primitive or the input if the input isn't a java primitive
+ *
+ * @param simpleType String
+ * @return the corresponding object wrapper type simple name of the input if the input is the name of a primitive java
+ * type. The input itself if not. (e.g. "int" results in "Integer")
+ * @throws ClassNotFoundException should not occur.
+ */
+ public String boxJavaPrimitives(String simpleType) throws ClassNotFoundException {
+
+ if (equalsJavaPrimitive(simpleType)) {
+ return ClassUtils.primitiveToWrapper(ClassUtils.getClass(simpleType)).getSimpleName();
+ } else {
+ return simpleType;
+ }
+
+ }
+
+ /**
+ * Returns the simple name of the type of a field in the pojoClass. If the type is a java primitive the name of the
+ * wrapper class is returned
+ *
+ * @param pojoClass {@link Class} the class object of the pojo
+ * @param fieldName {@link String} the name of the field
+ * @return String. The simple name of the field's type. The simple name of the wrapper class in case of java
+ * primitives
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public String boxJavaPrimitives(Class> pojoClass, String fieldName) throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+
+ if (equalsJavaPrimitive(pojoClass, fieldName)) {
+ return ClassUtils.primitiveToWrapper(pojoClass.getDeclaredField(fieldName).getType()).getSimpleName();
+ } else {
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ throw new IllegalAccessError("Could not find field " + fieldName + " in class " + pojoClass);
+ } else {
+ return field.getType().getSimpleName();
+ }
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive
+ *
+ * @param simpleType the type to be checked
+ * @return true iff simpleType is a Java primitive
+ */
+ public boolean equalsJavaPrimitive(String simpleType) {
+
+ try {
+ return ClassUtils.getClass(simpleType).isPrimitive();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive or wrapper
+ *
+ * @param simpleType the type to be checked
+ * @return true iff simpleType is a Java primitive or wrapper
+ */
+ public boolean equalsJavaPrimitiveOrWrapper(String simpleType) {
+
+ try {
+ return ClassUtils.isPrimitiveOrWrapper(ClassUtils.getClass(simpleType));
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the type of the field in the pojo's class is a java primitive
+ *
+ * @param pojoClass the {@link Class} object of the pojo
+ * @param fieldName the name of the field to be checked
+ * @return true iff the field is a java primitive
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean equalsJavaPrimitive(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ return false;
+ }
+
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ return false;
+ } else {
+ return field.getType().isPrimitive();
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive or a Java primitive array
+ *
+ * @param simpleType the Type name to be checked
+ * @return true iff {@link #equalsJavaPrimitive(String)} is true or if simpleType is an array with a primitive
+ * component
+ */
+ public boolean equalsJavaPrimitiveIncludingArrays(String simpleType) {
+
+ Class> klasse;
+
+ try {
+ klasse = ClassUtils.getClass(simpleType).getComponentType();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ return equalsJavaPrimitive(simpleType) || (klasse != null && klasse.isPrimitive());
+ }
+
+ /**
+ * Checks if the given field in the pojo class is a java primitive or an array of java primitives
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldName the name of the field to be checked
+ * @return true iff {@link #equalsJavaPrimitive(Class, String)} is true or the field is an array of primitives
+ * @throws NoSuchFieldException indicating something awfully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean equalsJavaPrimitiveIncludingArrays(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ return equalsJavaPrimitive(pojoClass, fieldName) || (pojoClass.getDeclaredField(fieldName).getType().isArray()
+ && pojoClass.getDeclaredField(fieldName).getType().getComponentType().isPrimitive());
+ }
+
+ /**
+ * Returns a cast statement for a given (java primitive, variable name) pair or nothing if the type isn't a java
+ * primitive
+ *
+ * @param simpleType Java Type
+ * @param varName Variable name
+ * @return String either of the form '((Java Primitive Object Type)varName)' if simpleType is a primitive or the empty
+ * String otherwise
+ * @throws ClassNotFoundException should not occur
+ */
+ public String castJavaPrimitives(String simpleType, String varName) throws ClassNotFoundException {
+
+ if (equalsJavaPrimitive(simpleType)) {
+ return String.format("((%1$s)%2$s)", boxJavaPrimitives(simpleType), varName);
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * Returns a cast statement for a given (java primitive, variable name) pair or nothing if the type isn't a java
+ * primitive
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldName the name of the field to be casted
+ * @return if fieldName points to a primitive field then a casted statement (e.g. for an int field:
+ * '((Integer)field)') or an empty String otherwise
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public String castJavaPrimitives(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ if (equalsJavaPrimitive(pojoClass, fieldName)) {
+ return String.format("((%1$s)%2$s)", boxJavaPrimitives(pojoClass, fieldName), fieldName);
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * @param pojoClass {@link Class} the class object of the pojo
+ * @param fieldName {@link String} the name of the field
+ * @return true if the field is an instance of java.utils.Collections
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean isCollection(Class> pojoClass, String fieldName) throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ return false;
+ }
+
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ return false;
+ } else {
+ return Collection.class.isAssignableFrom(field.getType());
+ }
+
+ }
+
+ /**
+ * Returns the Ext Type to a given java type
+ *
+ * @param simpleType any java type's simple name
+ * @return corresponding Ext type
+ */
+ public String getExtType(String simpleType) {
+
+ switch (simpleType) {
+ case "short":
+ case "Short":
+ case "int":
+ case "Integer":
+ case "long":
+ case "Long":
+ return "Integer";
+ case "float":
+ case "Float":
+ case "double":
+ case "Double":
+ return "Number";
+ case "boolean":
+ case "Boolean":
+ return "Boolean";
+ case "char":
+ case "Character":
+ case "String":
+ return "String";
+ case "Date":
+ return "Date";
+ default:
+ return "Field";
+ }
+ }
+
+ /**
+ * returns the Angular5 type associated with a Java primitive
+ *
+ * @param simpleType :{@link String} the type to be parsed
+ * @return the corresponding Angular type or 'any' otherwise
+ */
+ public String getAngularType(String simpleType) {
+
+ switch (simpleType) {
+ case "boolean":
+ return "boolean";
+ case "Boolean":
+ return "boolean";
+ case "short":
+ return "number";
+ case "Short":
+ return "number";
+ case "int":
+ return "number";
+ case "Integer":
+ return "number";
+ case "long":
+ return "number";
+ case "Long":
+ return "number";
+ case "float":
+ return "number";
+ case "Float":
+ return "number";
+ case "double":
+ return "number";
+ case "Double":
+ return "number";
+ case "char":
+ return "string";
+ case "Character":
+ return "string";
+ case "String":
+ return "string";
+ case "byte":
+ return "number";
+ default:
+ return "any";
+ }
+ }
+
+ /**
+ * returns the class name of the return type of a specific method.
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName {@link String} the name of the method
+ * @return the class name of the return type of the specified method
+ * @throws SecurityException If no method of the given name can be found
+ * @throws NoSuchMethodException If no method of the given name can be found
+ */
+ public String getReturnType(Class> pojoClass, String methodName) throws NoSuchMethodException, SecurityException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+ String s = "-";
+ Method method = findMethod(pojoClass, methodName);
+ if (method != null && !method.getReturnType().equals(Void.TYPE)) {
+ s = method.getReturnType().toString();
+ s = s.substring(s.lastIndexOf('.') + 1, s.length());
+ }
+ return s;
+ }
+
+ /**
+ *
+ * This methods returns the return type of the method in the given pojoClass which are annotated with the parameter
+ * annotatedClass
+ *
+ * @param pojoClass - The class in which to find if it has methods with annotatedClass
+ * @param annotatedClassName - The annotation which needs to be found
+ * @return Return type of the method annotated with the given annotation, else "null"
+ * @throws ClassNotFoundException if the annotated class name could not be found in the class path
+ */
+ @SuppressWarnings("unchecked")
+ public String getReturnTypeOfMethodAnnotatedWith(Class> pojoClass, String annotatedClassName)
+ throws ClassNotFoundException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+
+ Method[] methods = pojoClass.getDeclaredMethods();
+ for (Method method : methods) {
+ if (!method.getName().startsWith("get")) {
+ continue;
+ }
+ for (Annotation a : method.getAnnotations()) {
+ // better if (method.isAnnotationPresent(classObj)) {, but postponed as of different class
+ // loaders of a.getClass() and pojoClass.getClass()
+ if (a.getClass().getCanonicalName().equals(annotatedClassName)) {
+ return method.getReturnType().getSimpleName();
+ }
+ }
+ }
+ return "null";
+ }
+
+ /**
+ * returns the HTTP request type corresponding to an annotation type
+ *
+ * @param annotations The annotation to get the type name of
+ * @return the HTTP request type name of the selected annotation
+ */
+ public String getRequestType(Map annotations) {
+
+ if (annotations.containsKey("javax_ws_rs_GET")) {
+ return "GET";
+ } else if (annotations.containsKey("javax_ws_rs_PUT")) {
+ return "PUT";
+ } else if (annotations.containsKey("javax_ws_rs_POST")) {
+ return "POST";
+ } else if (annotations.containsKey("javax_ws_rs_DELETE")) {
+ return "DELETE";
+ } else if (annotations.containsKey("javax_ws_rs_PATCH")) {
+ return "PATCH";
+ } else {
+ return "-";
+ }
+ }
+
+ /**
+ * Helper method to find a class's specific method
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName The name of the method to be found
+ * @return The method object of the method to be found, null if it wasn't found
+ */
+ private Method findMethod(Class> pojoClass, String methodName) {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+ for (Method m : pojoClass.getMethods()) {
+ if (m.getName().equals(methodName)) {
+ return m;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Checks whether the class given by the full qualified name is an enum
+ *
+ * @param className full qualified class name
+ * @return true
if the class is an enum, false
otherwise
+ */
+ public boolean isEnum(String className) {
+
+ try {
+ return ClassUtils.getClass(className).isEnum();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), className);
+ return false;
+ }
+ }
+
+ /**
+ * Returns the first enum value of an enum class
+ *
+ * @param className full qualified class name
+ * @return the first enum value name found in order
+ */
+ public String getFirstEnumValue(String className) {
+
+ try {
+ Class> enumClass = ClassUtils.getClass(className);
+ Field[] declaredFields = enumClass.getDeclaredFields();
+ if (declaredFields.length > 0) {
+ return declaredFields[0].getName();
+ } else {
+ return null;
+ }
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), className);
+ return null;
+ }
+ }
+}
diff --git a/cobigen-templates/crud-java-ea-uml/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/uml/Connector.java b/cobigen-templates/crud-java-ea-uml/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/uml/Connector.java
new file mode 100644
index 0000000000..fd1a9c838d
--- /dev/null
+++ b/cobigen-templates/crud-java-ea-uml/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/uml/Connector.java
@@ -0,0 +1,104 @@
+package com.devonfw.cobigen.templates.devon4j.utils.uml;
+
+/**
+ * Connector is one association between classes in a class diagram. This class is used for storing that data, for later
+ * developing templates.
+ */
+public class Connector {
+
+ private String counterpartName = "";
+
+ private String counterpartMultiplicity = "";
+
+ private String className;
+
+ private String multiplicity;
+
+ final Boolean ISSOURCE;
+
+ final Boolean ISTARGET;
+
+ /**
+ * @param className The name of the connector
+ * @param multiplicity The multiplicity of the target of this connector
+ * @param isSource True if the connector is the source, false if it is the target
+ */
+ public Connector(String className, String multiplicity, boolean isSource) {
+
+ this.className = className;
+ this.multiplicity = multiplicity;
+ this.ISSOURCE = isSource;
+ this.ISTARGET = !isSource;
+ }
+
+ /**
+ * @return className name of the class
+ */
+ public String getClassName() {
+
+ return this.className;
+ }
+
+ /**
+ * @param className name of the class
+ */
+ public void setClassName(String className) {
+
+ this.className = className;
+ }
+
+ /**
+ * @return multiplicity
+ */
+ public String getMultiplicity() {
+
+ return this.multiplicity;
+ }
+
+ /**
+ * @param multiplicity multiplicity of the connection
+ */
+ public void setMultiplicity(String multiplicity) {
+
+ this.multiplicity = multiplicity;
+ }
+
+ /**
+ * @return counterpartName
+ */
+ public String getCounterpartName() {
+
+ return this.counterpartName;
+ }
+
+ /**
+ * @param counterpartName Name of the counter part entity
+ */
+ public void setCounterpartName(String counterpartName) {
+
+ this.counterpartName = counterpartName;
+ }
+
+ /**
+ * @return counterpartMultiplicity
+ */
+ public String getCounterpartMultiplicity() {
+
+ return this.counterpartMultiplicity;
+ }
+
+ /**
+ * @param counterpartMuliplicity multiplicity of the counter part entity
+ */
+ public void setCounterpartMultiplicity(String counterpartMuliplicity) {
+
+ this.counterpartMultiplicity = counterpartMuliplicity;
+ }
+
+ @Override
+ public String toString() {
+
+ return this.ISSOURCE + " " + this.className + " " + this.multiplicity + " --> " + this.counterpartName + " "
+ + this.counterpartMultiplicity + " " + this.ISTARGET;
+ }
+}
diff --git a/cobigen-templates/crud-java-ea-uml/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/uml/UmlUtil.java b/cobigen-templates/crud-java-ea-uml/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/uml/UmlUtil.java
new file mode 100644
index 0000000000..0d8f745615
--- /dev/null
+++ b/cobigen-templates/crud-java-ea-uml/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/uml/UmlUtil.java
@@ -0,0 +1,343 @@
+package com.devonfw.cobigen.templates.devon4j.utils.uml;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import org.apache.commons.lang3.text.WordUtils;
+import org.w3c.dom.Attr;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import com.devonfw.cobigen.templates.devon4j.utils.DevonfwUtil;
+
+/**
+ *
+ */
+public class UmlUtil {
+
+ /**
+ * List of connectors
+ */
+ private List connectors = new ArrayList<>();
+
+ /**
+ * For generating the variables and methods (Getters and Setters) of all the connected classes to this class
+ *
+ * @param isImpl Boolean: Is implementation tag needed
+ * @param isOverride Boolean: Is override tag needed
+ * @return String: Contains all the generated text
+ */
+ public String generateConnectorsVariablesMethodsText(boolean isImpl, boolean isOverride) {
+
+ String textContent = generateText(isImpl, isOverride);
+
+ this.connectors = new ArrayList();
+
+ return textContent;
+ }
+
+ /**
+ * Stores connector's source and target in HashMaps for further generation
+ *
+ * @param source source object
+ * @param target target object
+ * @param className name of the class
+ */
+ public void resolveConnectorsContent(Object source, Object target, String className) {
+
+ Node sourceNode = (Node) source;
+ Node targetNode = (Node) target;
+
+ HashMap sourceHash = new HashMap<>();
+ NodeList childs = sourceNode.getChildNodes();
+ for (int i = 0; i < childs.getLength(); i++) {
+ sourceHash.put(childs.item(i).getNodeName(), childs.item(i));
+ }
+
+ HashMap targetHash = new HashMap<>();
+ childs = targetNode.getChildNodes();
+ for (int i = 0; i < childs.getLength(); i++) {
+ targetHash.put(childs.item(i).getNodeName(), childs.item(i));
+ }
+
+ setConnectorsContent(sourceHash, targetHash, className);
+ }
+
+ /**
+ * Sets to the Connectors class the information retrieved from source and target tags. Only sets the classes that are
+ * connected to our class
+ *
+ * @param sourceHash Source hash
+ * @param targetHash Target hash
+ * @param className name of the class
+ */
+ public void setConnectorsContent(HashMap, ?> sourceHash, HashMap, ?> targetHash, String className) {
+
+ Connector sourceConnector = null;
+ Connector targetConnector = null;
+ boolean isTarget = false;
+ boolean isSource = false;
+
+ String sourceName = getClassName(sourceHash);
+ String sourceMultiplicity = getMultiplicity(sourceHash);
+ if (sourceName.equals(className)) {
+ isSource = true;
+ }
+
+ String targetName = getClassName(targetHash);
+ String targetMultiplicity = getMultiplicity(targetHash);
+ if (sourceName.equals(className)) {
+ isTarget = true;
+ }
+
+ if (isSource) {
+ sourceConnector = getConnector(sourceHash, true, targetMultiplicity, targetName);
+ this.connectors.add(sourceConnector);
+ } else if (isTarget) {
+ targetConnector = getConnector(targetHash, false, sourceMultiplicity, sourceName);
+ this.connectors.add(targetConnector);
+ }
+ }
+
+ /**
+ * Creates a Connector. The connector class is contains the information retrieved to the classes that are connected to
+ * our class
+ *
+ * @param nodeHash contains the node
+ * @param isSource true if I am source
+ * @param counterpartMultiplicity multiplicity of the counter part
+ * @param counterpartName Name of the counter part
+ * @return A newly created Connector
+ */
+ private Connector getConnector(HashMap, ?> nodeHash, boolean isSource, String counterpartMultiplicity,
+ String counterpartName) {
+
+ Connector connector = new Connector(getClassName(nodeHash), getMultiplicity(nodeHash), isSource);
+ connector.setCounterpartMultiplicity(counterpartMultiplicity);
+ connector.setCounterpartName(counterpartName);
+
+ return connector;
+ }
+
+ /**
+ * Extracts the multiplicity of a Connector from a Node
+ *
+ * @param nodeHash The node to get the multiplicity of
+ * @return The multiplicity of the connector
+ */
+ private String getMultiplicity(HashMap, ?> nodeHash) {
+
+ if (nodeHash.containsKey("type")) {
+ Node node = (Node) nodeHash.get("type");
+ NamedNodeMap attrs = node.getAttributes();
+ for (int j = 0; j < attrs.getLength(); j++) {
+ Attr attribute = (Attr) attrs.item(j);
+ if (attribute.getName().equals("multiplicity")) {
+ return attribute.getValue();
+ }
+ }
+ }
+ return "1";
+ }
+
+ /**
+ * Extracts the name of a Connector from a Node
+ *
+ * @param nodeHash The node to get the name of
+ * @return The name of the connector
+ */
+ private String getClassName(HashMap, ?> nodeHash) {
+
+ if (nodeHash.containsKey("model")) {
+ Node node = (Node) nodeHash.get("model");
+ NamedNodeMap attrs = node.getAttributes();
+ for (int j = 0; j < attrs.getLength(); j++) {
+ Attr attribute = (Attr) attrs.item(j);
+ if (attribute.getName().equals("name")) {
+ return attribute.getValue();
+ }
+ }
+ }
+ return "ErrorClassName";
+ }
+
+ /**
+ * @param isImpl true if this is called from an Implementation template
+ * @param isOverride true if this is called from an Entity template
+ * @return Generated text
+ */
+ public String generateText(boolean isImpl, boolean isOverride) {
+
+ String content = "";
+ if (isImpl) {
+ for (Connector connector : this.connectors) {
+ String connectedClassName = connector.getCounterpartName();
+ String multiplicity = connector.getCounterpartMultiplicity();
+ if (multiplicity == null || multiplicity.equals("1")) {
+ content += "\n\n\tprivate " + connectedClassName + "Entity " + connectedClassName.toLowerCase() + ";";
+ } else if (multiplicity != null && multiplicity.equals("*")) {
+ content += "\n\n\tprivate List<" + connectedClassName + "Entity> "
+ + new DevonfwUtil().removePlural(connectedClassName.toLowerCase()) + "s;";
+ }
+ }
+ }
+
+ for (Connector connector : this.connectors) {
+ String connectedClassName = connector.getCounterpartName();
+ String multiplicity = connector.getCounterpartMultiplicity();
+ if (multiplicity == null || multiplicity.equals("1")) {
+
+ content += "\n\n\t";
+ if (isOverride) {
+ content += "@Override\n\t";
+ }
+ if (isImpl) {
+ content += getRelationshipAnnotations(connector) + "\n\t";
+ content += "public " + connectedClassName + "Entity get" + connectedClassName + "()";
+ } else {
+ content += "public Long get" + connectedClassName + "Id()";
+ }
+ if (isImpl) {
+ content += "{" + "\n\t\treturn this." + connectedClassName.toLowerCase() + ";" + "\n\t}";
+ } else {
+ content += ";";
+ }
+
+ content += "\n\n\t";
+ if (isOverride) {
+ content += "@Override\n\t";
+ }
+ if (isImpl) {
+ content += "public void set" + connectedClassName + "(" + connectedClassName + "Entity "
+ + connectedClassName.toLowerCase() + ")";
+ } else {
+ content += "public void set" + connectedClassName + "Id(Long " + connectedClassName.toLowerCase() + "Id)";
+ }
+ if (isImpl) {
+ content += "{" + "\n\t\tthis." + connectedClassName.toLowerCase() + " = " + connectedClassName.toLowerCase()
+ + ";" + "\n\t}";
+ } else {
+ content += ";";
+ }
+ // Now w generate the get and set IDs methods for the implementation
+ if (isImpl) {
+ // getter
+ content += "\n\n\t";
+ content += "@Override\n\t";
+ content += "public Long get" + connectedClassName + "Id()";
+ content += "{" + "\n\t\tif(this." + connectedClassName.toLowerCase() + " == null){";
+ content += "\n\t\treturn null;\n\t}";
+ content += "\n\t\treturn this." + connectedClassName.toLowerCase() + ".getId();" + "\n\t}";
+ // setter
+ content += "\n\n\t";
+ content += "@Override\n\t";
+ content += "public void set" + connectedClassName + "Id(Long " + connectedClassName.toLowerCase() + "Id)";
+ content += "{" + "\n\t\tif(" + connectedClassName.toLowerCase() + "Id == null){";
+ content += "\n\t\tthis." + connectedClassName.toLowerCase() + " = null;\n\t}";
+ content += "else {\n\t";
+ content += connectedClassName + "Entity " + connectedClassName.toLowerCase() + "Entity = new "
+ + connectedClassName + "Entity();\n\n\t";
+ content += connectedClassName.toLowerCase() + ".setId(" + connectedClassName.toLowerCase() + "Id);\n\n\t";
+ content += "this." + connectedClassName.toLowerCase() + " " + "= " + connectedClassName.toLowerCase()
+ + "Entity;\n\n\t}";
+ content += "\n\n\t}";
+ }
+
+ } else if (multiplicity != null && multiplicity.equals("*") && isImpl) {
+
+ content += "\n\n\t";
+ if (isOverride) {
+ content += "@Override\n\t";
+ }
+ content += getRelationshipAnnotations(connector) + "\n\t";
+ content += "public List<" + connectedClassName + "Entity> get"
+ + new DevonfwUtil().removePlural(connectedClassName) + "s()";
+ content += "{" + "\n\t\treturn this." + new DevonfwUtil().removePlural(connectedClassName.toLowerCase()) + "s;"
+ + "\n\t}";
+ content += "\n\n\t";
+ if (isOverride) {
+ content += "@Override\n\t";
+ }
+ content += "public void set" + new DevonfwUtil().removePlural(connectedClassName) + "s(List<" + connectedClassName
+ + "Entity> " + new DevonfwUtil().removePlural(connectedClassName.toLowerCase()) + "s)";
+ content += "{" + "\n\t\tthis." + new DevonfwUtil().removePlural(connectedClassName.toLowerCase()) + "s = "
+ + new DevonfwUtil().removePlural(connectedClassName.toLowerCase()) + "s;" + "\n\t}";
+ }
+ }
+ return content;
+ }
+
+ /**
+ * Generates the annotations of all the connected classes
+ *
+ * @param source The source connector that is used to generate relationship annotations
+ * @return relationship string with all the annotations for the connected classes
+ */
+ private String getRelationshipAnnotations(Connector source) {
+
+ String relationship = "";
+ if (source.ISSOURCE) {
+ if (source.getMultiplicity() == null || source.getMultiplicity().equals("1")) {
+ if (source.getCounterpartMultiplicity() == null || source.getCounterpartMultiplicity().equals("1")) {
+ relationship = "@OneToOne()" + "\n\t@JoinColumn(name = \"" + source.getCounterpartName() + "Id\")";
+ } else if (source.getCounterpartMultiplicity().equals("*")) {
+ relationship = "@OneToMany(fetch = FetchType.LAZY)\n\t@JoinColumn(name = \""
+ + WordUtils.capitalize(source.getCounterpartName()) + "id\")";
+ }
+ } else if (source.getMultiplicity().equals("*")) {
+ if (source.getCounterpartMultiplicity().equals("*")) {
+ relationship += "@ManyToMany()";
+ relationship += "\n\t@JoinTable(name = \"" + WordUtils.capitalize(source.getCounterpartName())
+ + WordUtils.capitalize(source.getClassName()) + "\", joinColumns = @JoinColumn(name = \""
+ + source.getClassName() + "Id\"), inverseJoinColumns = @JoinColumn(name = \""
+ + source.getCounterpartName() + "Id\"))";
+ } else if (source.getCounterpartMultiplicity().equals("1")) {
+ relationship += "@ManyToOne(fetch = FetchType.LAZY)\n\t@JoinColumn(name = \"" + source.getCounterpartName()
+ + "Id\")";
+ }
+ }
+ } else if (source.ISTARGET) {
+ if (source.getCounterpartMultiplicity() == null || source.getCounterpartMultiplicity().equals("1")) {
+ if (source.getMultiplicity() == null || source.getMultiplicity().equals("1")) {
+ relationship = "@OneToOne()" + "\n\t"//
+ + "@JoinColumn(name = \"" + source.getCounterpartName() + "Id\")";
+ } else if (source.getMultiplicity().equals("*")) {
+ relationship += "@ManyToOne(fetch = FetchType.LAZY)\n\t"//
+ + "@JoinColumn(name = \"" + source.getCounterpartName() + "Id\")";
+ }
+ } else if (source.getCounterpartMultiplicity().equals("*")) {
+ if (source.getMultiplicity().equals("*")) {
+ relationship += "@ManyToMany(mappedBy = \""
+ + new DevonfwUtil().removePlural(source.getClassName()).toLowerCase() + "s\")";
+ } else if (source.getMultiplicity().equals("1")) {
+ relationship = "@OneToMany(fetch = FetchType.LAZY, mappedBy = \"" + source.getCounterpartName().toLowerCase()
+ + "\")";
+ }
+ }
+ }
+ return relationship;
+ }
+
+ /**
+ * Returns connectors
+ *
+ * @return connectors
+ */
+ public List getConnectors() {
+
+ return this.connectors;
+ }
+
+ /**
+ * Sets a new connector list
+ *
+ * @param connectors The new list of connectors
+ */
+ public void setConnectors(List connectors) {
+
+ this.connectors = connectors;
+ }
+
+}
diff --git a/cobigen-templates/crud-java-server-app-complex/pom.xml b/cobigen-templates/crud-java-server-app-complex/pom.xml
index 82a06f6b0c..7876d0c5f7 100644
--- a/cobigen-templates/crud-java-server-app-complex/pom.xml
+++ b/cobigen-templates/crud-java-server-app-complex/pom.xml
@@ -10,4 +10,10 @@
${revision}
+
+
+ org.apache.commons
+ commons-lang3
+
+
diff --git a/cobigen-templates/crud-java-server-app-complex/src/main/java/com/devonfw/cobigen/templates/devon4j/constants/Field.java b/cobigen-templates/crud-java-server-app-complex/src/main/java/com/devonfw/cobigen/templates/devon4j/constants/Field.java
new file mode 100644
index 0000000000..5376daaea9
--- /dev/null
+++ b/cobigen-templates/crud-java-server-app-complex/src/main/java/com/devonfw/cobigen/templates/devon4j/constants/Field.java
@@ -0,0 +1,48 @@
+package com.devonfw.cobigen.templates.devon4j.constants;
+
+/**
+ * Contains the used keys for the pojo field mapping
+ */
+public enum Field {
+
+ /**
+ * Name of the field
+ */
+ NAME("name"),
+ /**
+ * Type of the field
+ */
+ TYPE("type"),
+ /**
+ * Canonical Type of the field
+ */
+ CANONICAL_TYPE("canonicalType"),
+ /**
+ * The Javadoc of the field
+ */
+ JAVA_DOC("javaDoc"),
+ /**
+ * Annotations
+ */
+ ANNOTATIONS("annotations");
+
+ /**
+ * key value
+ */
+ private String value;
+
+ /**
+ * @param value of the key
+ */
+ Field(String value) {
+
+ this.value = value;
+ }
+
+ @Override
+ public String toString() {
+
+ return this.value;
+ }
+
+}
diff --git a/cobigen-templates/crud-java-server-app-complex/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/DevonfwUtil.java b/cobigen-templates/crud-java-server-app-complex/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/DevonfwUtil.java
new file mode 100644
index 0000000000..36e39b5e06
--- /dev/null
+++ b/cobigen-templates/crud-java-server-app-complex/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/DevonfwUtil.java
@@ -0,0 +1,450 @@
+package com.devonfw.cobigen.templates.devon4j.utils;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.NodeList;
+
+import com.devonfw.cobigen.templates.devon4j.constants.Field;
+import com.sun.org.apache.xerces.internal.dom.DeferredElementNSImpl;
+
+/**
+ * A class for shared devon4j specific functions in the templates
+ *
+ */
+@SuppressWarnings("restriction")
+public class DevonfwUtil {
+
+ /**
+ * Check whether the given 'canonicalType' is a devon4j Entity, which is declared in the given 'component'
+ *
+ * @param canonicalType the type name
+ * @param component the component name
+ * @return true iff the canonicalType is a devon Entity
+ */
+ public boolean isEntityInComponent(String canonicalType, String component) {
+
+ return canonicalType.matches(String.format(".+%1$s\\.dataaccess\\.api\\.[A-Za-z0-9]+Entity(<.*)?", component));
+ }
+
+ /**
+ * Check whether the given 'canonicalType' is declared in the given 'component'
+ *
+ * @param canonicalType the type name
+ * @param component the component name
+ * @return true iff the canonicalType is inside the given component
+ */
+ public boolean isTypeInComponent(String canonicalType, String component) {
+
+ return canonicalType.matches(String.format("%1$s.[A-Za-z0-9]+(<.*)?", component));
+ }
+
+ /**
+ * Determines the ID getter for a given 'field' dependent on whether the getter should access the ID via an object
+ * reference or a direct ID getter
+ *
+ * @param field the field
+ * @param byObjectReference boolean
+ * @param component the devon4j component name
+ * @return 'get' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)} + '()' with
+ * capitalize=true
+ */
+ public String resolveIdGetter(Map field, boolean byObjectReference, String component) {
+
+ // If field comes from an UML file
+ if (field.getClass().toGenericString().contains("freemarker.ext.beans.HashAdapter")) {
+ DeferredElementNSImpl umlNode = (DeferredElementNSImpl) field;
+ return resolveIdGetter(umlNode, byObjectReference, component);
+ }
+ return "get" + resolveIdVariableNameOrSetterGetterSuffix(field, byObjectReference, true, component) + "()";
+ }
+
+ /**
+ * Determines the ID getter for a given 'field' dependent on whether the getter should access the ID via an object
+ * reference or a direct ID getter
+ *
+ * This method is used when the field parameter comes from an UML file. The name and type of the attributes must be
+ * pre-processed for later inserting them inside the HashMap.
+ *
+ * @param field the field
+ * @param byObjectReference boolean
+ * @param component the devon4j component name
+ * @return 'get' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)} + '()' with
+ * capitalize=true
+ */
+ public String resolveIdGetter(DeferredElementNSImpl field, boolean byObjectReference, String component) {
+
+ HashMap nodeHash = new HashMap<>();
+
+ // Putting the name of the attribute to the hash
+ nodeHash.put(Field.NAME.toString(), field.getAttribute("name"));
+
+ // Putting the type of the attribute to the hash
+ NodeList childs = field.getChildNodes();
+ for (int i = 0; i < childs.getLength(); i++) {
+ // Retrieve "type" tag
+ if (childs.item(i).getNodeName().equals("type")) {
+ NamedNodeMap attrs = childs.item(i).getAttributes();
+ for (int j = 0; j < attrs.getLength(); j++) {
+ Attr attribute = (Attr) attrs.item(j);
+ // Try to find the attribute that contains the type
+ if (attribute.getName().equals("xmi:idref")) {
+ nodeHash.put(Field.TYPE.toString(), attribute.getName().replace("EAJava_", ""));
+ }
+ }
+ }
+ }
+ return "get" + resolveIdVariableNameOrSetterGetterSuffix(nodeHash, byObjectReference, true, component) + "()";
+
+ }
+
+ /**
+ * Determines the ID getter for a given 'field' dependent on whether the getter should access the ID via an object
+ * reference or a direct ID getter
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldMap the field mapping
+ * @param byObjectReference boolean
+ * @param component the devon4j component name
+ * @return 'get' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)} + '()' with
+ * capitalize=true
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdGetter(Class> pojoClass, Map fieldMap, boolean byObjectReference,
+ String component) throws NoSuchFieldException, SecurityException {
+
+ return "get" + resolveIdVariableNameOrSetterGetterSuffix(pojoClass, fieldMap, byObjectReference, true, component)
+ + "()";
+ }
+
+ /**
+ * same as {@link #resolveIdGetter(Map, boolean, String)} but with byObjectReference=false and component=""
+ *
+ * @param field the field
+ * @return 'get' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map,boolean,boolean,String)} + '()' with
+ * capitalize=true
+ */
+ public String resolveIdGetter(Map field) {
+
+ return this.resolveIdGetter(field, false, "");
+ }
+
+ /**
+ * same as {@link #resolveIdGetter(Class,Map,boolean,String)} but with byObjectReference=false and component=""
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldMap the field mapping
+ * @return 'get' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map,boolean,boolean,String)} + '()' with
+ * capitalize=true
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdGetter(Class> pojoClass, Map fieldMap)
+ throws NoSuchFieldException, SecurityException {
+
+ return resolveIdGetter(pojoClass, fieldMap, false, "");
+ }
+
+ /**
+ * Determines the ID setter for a given 'field' dependent on whether the setter should access the ID via an object
+ * reference or a direct ID setter. In contrast to resolveIdGetter, this function does not generate the function
+ * parenthesis to enable parameter declaration.
+ *
+ * @param field the field
+ * @param byObjectReference boolean
+ * @param component the devon4j component name
+ * @return 'set' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)} with
+ * capitalize=true
+ */
+ public String resolveIdSetter(Map field, boolean byObjectReference, String component) {
+
+ return "set" + resolveIdVariableNameOrSetterGetterSuffix(field, byObjectReference, true, component);
+ }
+
+ /**
+ * same as {@link #resolveIdSetter(Map, boolean, String)} but with byObjectReference=false and component=""
+ *
+ * @param field the field
+ * @return 'set' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)} with
+ * capitalize=true
+ */
+ public String resolveIdSetter(Map field) {
+
+ return this.resolveIdSetter(field, false, "");
+ }
+
+ /**
+ * Determines the ID setter for a given 'field' dependent on whether the setter should access the ID via an object
+ * reference or a direct ID setter. In contrast to resolveIdGetter, this function does not generate the function
+ * parenthesis to enable parameter declaration.
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldMap the field mapping
+ * @param byObjectReference boolean
+ * @param component the devon4j component name
+ * @return 'set'+ {@link #resolveIdVariableNameOrSetterGetterSuffix(Map,boolean,boolean,String)} with capitalize=true
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdSetter(Class> pojoClass, Map fieldMap, boolean byObjectReference,
+ String component) throws NoSuchFieldException, SecurityException {
+
+ return "set" + resolveIdVariableNameOrSetterGetterSuffix(pojoClass, fieldMap, byObjectReference, true, component);
+ }
+
+ /**
+ * same as {@link #resolveIdSetter(Class,Map,boolean,String)} but with byObjectReference=false and component=""
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldMap the field mapping
+ * @return 'set' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map,boolean,boolean,String)} with capitalize=true
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdSetter(Class> pojoClass, Map fieldMap)
+ throws NoSuchFieldException, SecurityException {
+
+ return resolveIdSetter(pojoClass, fieldMap, false, "");
+ }
+
+ /**
+ * Determines the variable name for the id value of the 'field'
+ *
+ * @param field the field
+ * @return {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)}) with
+ * byObjectReference=false, capitalize=false and component=""
+ */
+ public String resolveIdVariableName(Map field) {
+
+ // the component is passed down as an empty string since byObjectReference is false and therefore the
+ // component is
+ // never touched
+ return resolveIdVariableNameOrSetterGetterSuffix(field, false, false, "");
+ }
+
+ /**
+ * Determines the variable name for the id value of the specified field in the pojo
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldMap the field mapping
+ * @return {@link #resolveIdVariableNameOrSetterGetterSuffix(Class, Map, boolean, boolean, String)}) with
+ * byObjectReference=false, capitalize=false and component=""
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdVariableName(Class> pojoClass, Map fieldMap)
+ throws NoSuchFieldException, SecurityException {
+
+ // the component is passed down as an empty string since byObjectReference is false and therefore the
+ // component is
+ // never touched
+ return resolveIdVariableNameOrSetterGetterSuffix(pojoClass, fieldMap, false, false, "");
+ }
+
+ /**
+ * Determines the ID setter/getter suffix for a given 'field' dependent on whether the setter/getter should access the
+ * ID via an object reference or a direct ID setter/getter
+ *
+ * @param field the field
+ * @param byObjectReference boolean
+ * @param capitalize if the field name should be capitalized
+ * @param component the devon4j component. Only needed if $byObjectReference is true
+ * @return idVariable name or getter/setter suffix
+ */
+ public String resolveIdVariableNameOrSetterGetterSuffix(Map field, boolean byObjectReference,
+ boolean capitalize, String component) {
+
+ String fieldName = (String) field.get(Field.NAME.toString());
+ if (capitalize) {
+ fieldName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
+ }
+ String suffix = "";
+
+ String fieldType = (String) field.get(Field.TYPE.toString());
+ String fieldCType = (String) field.get(Field.CANONICAL_TYPE.toString());
+ if (fieldType.contains("Entity")) {
+ if (fieldCType.startsWith("java.util.List") || fieldCType.startsWith("java.util.Set")) {
+ suffix = "Ids";
+ if (fieldName.endsWith("s")) {
+ // Assume trailing 's' as indicator for a plural
+ fieldName = fieldName.substring(0, fieldName.length() - 1);
+ }
+ } else {
+ suffix = "Id";
+ }
+ if (byObjectReference && isTypeInComponent(fieldCType, component)) {
+ // direct references for Entities in same component, so get id of the object reference
+ suffix = "().getId";
+ }
+ }
+
+ return fieldName + suffix;
+
+ }
+
+ /**
+ * Determines the ID setter/getter suffix for a given 'field' dependent on whether the setter/getter should access the
+ * ID via an object reference or a direct ID setter/getter
+ *
+ * @param pojoClass the {@link Class} object of the pojo
+ * @param fieldMap the field mapping
+ * @param byObjectReference boolean
+ * @param capitalize if the field name should be capitalized
+ * @param component the devon4j component. Only needed if byObjectReference is true
+ * @return idVariable name or getter/setter suffix
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdVariableNameOrSetterGetterSuffix(Class> pojoClass, Map fieldMap,
+ boolean byObjectReference, boolean capitalize, String component) throws NoSuchFieldException, SecurityException {
+
+ String resultName = (String) fieldMap.get(Field.NAME.toString());
+ if (capitalize) {
+ resultName = resultName.substring(0, 1).toUpperCase() + resultName.substring(1);
+ }
+ String suffix = "";
+ String fieldType = (String) fieldMap.get(Field.TYPE.toString());
+ String fieldName = (String) fieldMap.get(Field.NAME.toString());
+ if (fieldType.contains("Entity")) {
+ if (Collection.class.isAssignableFrom(pojoClass.getDeclaredField(fieldName).getType())) {
+ suffix = "Ids";
+ if (resultName.endsWith("s")) {
+ // Assume trailing 's' as indicator for a plural
+ resultName = resultName.substring(0, resultName.length() - 1);
+ }
+ } else {
+ suffix = "Id";
+ }
+ if (byObjectReference
+ && isEntityInComponent(pojoClass.getDeclaredField(fieldName).getType().getName(), component)) {
+ // direct references for Entities in same component, so get id of the object reference
+ suffix = "().getId";
+ }
+ }
+
+ return resultName + suffix;
+
+ }
+
+ /**
+ * Returns the argument type of the list or set from a field. If the string contains "Entity" it will remove that
+ * part. For example, if we have a List <SampleEntity> it will return "Sample"
+ *
+ * @param field the field
+ * @param pojoClass the object class of the Entity that contains the field
+ * @return fieldType argument of the list
+ * @throws SecurityException if field type could not accessed
+ * @throws NoSuchFieldException if field could not be found
+ */
+ public String getListArgumentType(Map field, Class> pojoClass)
+ throws NoSuchFieldException, SecurityException {
+
+ JavaUtil javaUtil = new JavaUtil();
+
+ String fieldType = (String) field.get(Field.TYPE.toString());
+ String fieldName = (String) field.get(Field.NAME.toString());
+
+ if (fieldType.contains("Entity")) {
+ if (javaUtil.isCollection(pojoClass, fieldName)) {
+
+ fieldType = fieldType.replace("Entity", "");
+ // Regex: Extracts the argument type of the list 'List' => type
+ String regex = "(?<=\\<).+?(?=\\>)";
+ Pattern pattern = Pattern.compile(regex);
+ Matcher regexMatcher = pattern.matcher(fieldType);
+
+ if (regexMatcher.find()) {
+ fieldType = regexMatcher.group(0);
+ }
+ }
+ }
+ return fieldType;
+
+ }
+
+ /**
+ * Converts all occurrences of devon4j Entity types in the given 'field' simple type (possibly generic) to Longs
+ *
+ * @param field the field
+ * @return the field type as String. If field type contains 'Entity' the result is Long
+ */
+ public String getSimpleEntityTypeAsLongReference(Map field) {
+
+ String fieldType = (String) field.get(Field.TYPE.toString());
+ if (fieldType.endsWith("Entity")) {
+ fieldType = fieldType.replaceAll("[^<>]+Entity", "Long");
+ }
+ return fieldType;
+ }
+
+ /**
+ * If the string last character is an 's', then it gets removed
+ *
+ * @param targetClassName string to remove plural
+ * @return string without 's'
+ */
+ public String removePlural(String targetClassName) {
+
+ if (targetClassName.charAt(targetClassName.length() - 1) == 's') {
+ targetClassName = targetClassName.substring(0, targetClassName.length() - 1);
+ }
+ return targetClassName;
+ }
+
+ /**
+ * Checks whether the operation with the given ID corresponds to any standard CRUD method name.
+ *
+ * @param operationId operation ID interpreted as method name
+ * @param entityName entity name to check standard CRUD methods for
+ * @return true
if the operation ID maps any standard CRUD method name, false
otherwise
+ */
+ public boolean isCrudOperation(String operationId, String entityName) {
+
+ if (operationId == null) {
+ return false;
+ }
+ String opIdLowerCase = operationId.toLowerCase();
+ String entityNameLowerCase = entityName.toLowerCase();
+ if (opIdLowerCase.contains(entityNameLowerCase)) {
+ return opIdLowerCase.equals("find" + entityNameLowerCase)
+ || opIdLowerCase.equals("find" + entityNameLowerCase + "Etos")
+ || opIdLowerCase.equals("delete" + entityNameLowerCase) || opIdLowerCase.equals("save" + entityNameLowerCase);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Converts the given media type to the spring Java enum value
+ *
+ * @param mediaType to be converted
+ * @return the spring enum value representing the given media type
+ */
+ public String getSpringMediaType(String mediaType) {
+
+ switch (mediaType) {
+ case "application/xml":
+ return "APPLICATION_XML_VALUE";
+ case "application / x-www-form-urlencoded":
+ return "APPLICATION_FORM_URLENCODED_VALUE";
+ case "multipart/form-data":
+ return "MULTIPART_FORM_DATA_VALUE";
+ case "text/plain":
+ return "TEXT_PLAIN_VALUE";
+ case "text/html":
+ return "TEXT_HTML_VALUE";
+ case "application/pdf":
+ return "APPLICATION_PDF_VALUE";
+ case "image/png":
+ return "IMAGE_PNG_VALUE";
+ default:
+ return "APPLICATION_JSON_VALUE";
+ }
+ }
+}
\ No newline at end of file
diff --git a/cobigen-templates/crud-java-server-app-complex/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java b/cobigen-templates/crud-java-server-app-complex/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java
new file mode 100644
index 0000000000..ced2f5fde2
--- /dev/null
+++ b/cobigen-templates/crud-java-server-app-complex/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java
@@ -0,0 +1,464 @@
+package com.devonfw.cobigen.templates.devon4j.utils;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.commons.lang3.ClassUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Provides type operations, mainly checks and casts for Java Primitives, to be used in the templates
+ *
+ */
+public class JavaUtil {
+
+ /**
+ * Logger for this class
+ */
+ private static final Logger LOG = LoggerFactory.getLogger(JavaUtil.class);
+
+ /**
+ * The constructor.
+ */
+ public JavaUtil() {
+
+ // Empty for CobiGen to automatically instantiate it
+ }
+
+ /**
+ * Returns the Object version of a Java primitive or the input if the input isn't a java primitive
+ *
+ * @param simpleType String
+ * @return the corresponding object wrapper type simple name of the input if the input is the name of a primitive java
+ * type. The input itself if not. (e.g. "int" results in "Integer")
+ * @throws ClassNotFoundException should not occur.
+ */
+ public String boxJavaPrimitives(String simpleType) throws ClassNotFoundException {
+
+ if (equalsJavaPrimitive(simpleType)) {
+ return ClassUtils.primitiveToWrapper(ClassUtils.getClass(simpleType)).getSimpleName();
+ } else {
+ return simpleType;
+ }
+
+ }
+
+ /**
+ * Returns the simple name of the type of a field in the pojoClass. If the type is a java primitive the name of the
+ * wrapper class is returned
+ *
+ * @param pojoClass {@link Class} the class object of the pojo
+ * @param fieldName {@link String} the name of the field
+ * @return String. The simple name of the field's type. The simple name of the wrapper class in case of java
+ * primitives
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public String boxJavaPrimitives(Class> pojoClass, String fieldName) throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+
+ if (equalsJavaPrimitive(pojoClass, fieldName)) {
+ return ClassUtils.primitiveToWrapper(pojoClass.getDeclaredField(fieldName).getType()).getSimpleName();
+ } else {
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ throw new IllegalAccessError("Could not find field " + fieldName + " in class " + pojoClass);
+ } else {
+ return field.getType().getSimpleName();
+ }
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive
+ *
+ * @param simpleType the type to be checked
+ * @return true iff simpleType is a Java primitive
+ */
+ public boolean equalsJavaPrimitive(String simpleType) {
+
+ try {
+ return ClassUtils.getClass(simpleType).isPrimitive();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive or wrapper
+ *
+ * @param simpleType the type to be checked
+ * @return true iff simpleType is a Java primitive or wrapper
+ */
+ public boolean equalsJavaPrimitiveOrWrapper(String simpleType) {
+
+ try {
+ return ClassUtils.isPrimitiveOrWrapper(ClassUtils.getClass(simpleType));
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the type of the field in the pojo's class is a java primitive
+ *
+ * @param pojoClass the {@link Class} object of the pojo
+ * @param fieldName the name of the field to be checked
+ * @return true iff the field is a java primitive
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean equalsJavaPrimitive(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ return false;
+ }
+
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ return false;
+ } else {
+ return field.getType().isPrimitive();
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive or a Java primitive array
+ *
+ * @param simpleType the Type name to be checked
+ * @return true iff {@link #equalsJavaPrimitive(String)} is true or if simpleType is an array with a primitive
+ * component
+ */
+ public boolean equalsJavaPrimitiveIncludingArrays(String simpleType) {
+
+ Class> klasse;
+
+ try {
+ klasse = ClassUtils.getClass(simpleType).getComponentType();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ return equalsJavaPrimitive(simpleType) || (klasse != null && klasse.isPrimitive());
+ }
+
+ /**
+ * Checks if the given field in the pojo class is a java primitive or an array of java primitives
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldName the name of the field to be checked
+ * @return true iff {@link #equalsJavaPrimitive(Class, String)} is true or the field is an array of primitives
+ * @throws NoSuchFieldException indicating something awfully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean equalsJavaPrimitiveIncludingArrays(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ return equalsJavaPrimitive(pojoClass, fieldName) || (pojoClass.getDeclaredField(fieldName).getType().isArray()
+ && pojoClass.getDeclaredField(fieldName).getType().getComponentType().isPrimitive());
+ }
+
+ /**
+ * Returns a cast statement for a given (java primitive, variable name) pair or nothing if the type isn't a java
+ * primitive
+ *
+ * @param simpleType Java Type
+ * @param varName Variable name
+ * @return String either of the form '((Java Primitive Object Type)varName)' if simpleType is a primitive or the empty
+ * String otherwise
+ * @throws ClassNotFoundException should not occur
+ */
+ public String castJavaPrimitives(String simpleType, String varName) throws ClassNotFoundException {
+
+ if (equalsJavaPrimitive(simpleType)) {
+ return String.format("((%1$s)%2$s)", boxJavaPrimitives(simpleType), varName);
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * Returns a cast statement for a given (java primitive, variable name) pair or nothing if the type isn't a java
+ * primitive
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldName the name of the field to be casted
+ * @return if fieldName points to a primitive field then a casted statement (e.g. for an int field:
+ * '((Integer)field)') or an empty String otherwise
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public String castJavaPrimitives(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ if (equalsJavaPrimitive(pojoClass, fieldName)) {
+ return String.format("((%1$s)%2$s)", boxJavaPrimitives(pojoClass, fieldName), fieldName);
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * @param pojoClass {@link Class} the class object of the pojo
+ * @param fieldName {@link String} the name of the field
+ * @return true if the field is an instance of java.utils.Collections
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean isCollection(Class> pojoClass, String fieldName) throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ return false;
+ }
+
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ return false;
+ } else {
+ return Collection.class.isAssignableFrom(field.getType());
+ }
+
+ }
+
+ /**
+ * Returns the Ext Type to a given java type
+ *
+ * @param simpleType any java type's simple name
+ * @return corresponding Ext type
+ */
+ public String getExtType(String simpleType) {
+
+ switch (simpleType) {
+ case "short":
+ case "Short":
+ case "int":
+ case "Integer":
+ case "long":
+ case "Long":
+ return "Integer";
+ case "float":
+ case "Float":
+ case "double":
+ case "Double":
+ return "Number";
+ case "boolean":
+ case "Boolean":
+ return "Boolean";
+ case "char":
+ case "Character":
+ case "String":
+ return "String";
+ case "Date":
+ return "Date";
+ default:
+ return "Field";
+ }
+ }
+
+ /**
+ * returns the Angular5 type associated with a Java primitive
+ *
+ * @param simpleType :{@link String} the type to be parsed
+ * @return the corresponding Angular type or 'any' otherwise
+ */
+ public String getAngularType(String simpleType) {
+
+ switch (simpleType) {
+ case "boolean":
+ return "boolean";
+ case "Boolean":
+ return "boolean";
+ case "short":
+ return "number";
+ case "Short":
+ return "number";
+ case "int":
+ return "number";
+ case "Integer":
+ return "number";
+ case "long":
+ return "number";
+ case "Long":
+ return "number";
+ case "float":
+ return "number";
+ case "Float":
+ return "number";
+ case "double":
+ return "number";
+ case "Double":
+ return "number";
+ case "char":
+ return "string";
+ case "Character":
+ return "string";
+ case "String":
+ return "string";
+ case "byte":
+ return "number";
+ default:
+ return "any";
+ }
+ }
+
+ /**
+ * returns the class name of the return type of a specific method.
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName {@link String} the name of the method
+ * @return the class name of the return type of the specified method
+ * @throws SecurityException If no method of the given name can be found
+ * @throws NoSuchMethodException If no method of the given name can be found
+ */
+ public String getReturnType(Class> pojoClass, String methodName) throws NoSuchMethodException, SecurityException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+ String s = "-";
+ Method method = findMethod(pojoClass, methodName);
+ if (method != null && !method.getReturnType().equals(Void.TYPE)) {
+ s = method.getReturnType().toString();
+ s = s.substring(s.lastIndexOf('.') + 1, s.length());
+ }
+ return s;
+ }
+
+ /**
+ *
+ * This methods returns the return type of the method in the given pojoClass which are annotated with the parameter
+ * annotatedClass
+ *
+ * @param pojoClass - The class in which to find if it has methods with annotatedClass
+ * @param annotatedClassName - The annotation which needs to be found
+ * @return Return type of the method annotated with the given annotation, else "null"
+ * @throws ClassNotFoundException if the annotated class name could not be found in the class path
+ */
+ @SuppressWarnings("unchecked")
+ public String getReturnTypeOfMethodAnnotatedWith(Class> pojoClass, String annotatedClassName)
+ throws ClassNotFoundException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+
+ Method[] methods = pojoClass.getDeclaredMethods();
+ for (Method method : methods) {
+ if (!method.getName().startsWith("get")) {
+ continue;
+ }
+ for (Annotation a : method.getAnnotations()) {
+ // better if (method.isAnnotationPresent(classObj)) {, but postponed as of different class
+ // loaders of a.getClass() and pojoClass.getClass()
+ if (a.getClass().getCanonicalName().equals(annotatedClassName)) {
+ return method.getReturnType().getSimpleName();
+ }
+ }
+ }
+ return "null";
+ }
+
+ /**
+ * returns the HTTP request type corresponding to an annotation type
+ *
+ * @param annotations The annotation to get the type name of
+ * @return the HTTP request type name of the selected annotation
+ */
+ public String getRequestType(Map annotations) {
+
+ if (annotations.containsKey("javax_ws_rs_GET")) {
+ return "GET";
+ } else if (annotations.containsKey("javax_ws_rs_PUT")) {
+ return "PUT";
+ } else if (annotations.containsKey("javax_ws_rs_POST")) {
+ return "POST";
+ } else if (annotations.containsKey("javax_ws_rs_DELETE")) {
+ return "DELETE";
+ } else if (annotations.containsKey("javax_ws_rs_PATCH")) {
+ return "PATCH";
+ } else {
+ return "-";
+ }
+ }
+
+ /**
+ * Helper method to find a class's specific method
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName The name of the method to be found
+ * @return The method object of the method to be found, null if it wasn't found
+ */
+ private Method findMethod(Class> pojoClass, String methodName) {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+ for (Method m : pojoClass.getMethods()) {
+ if (m.getName().equals(methodName)) {
+ return m;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Checks whether the class given by the full qualified name is an enum
+ *
+ * @param className full qualified class name
+ * @return true
if the class is an enum, false
otherwise
+ */
+ public boolean isEnum(String className) {
+
+ try {
+ return ClassUtils.getClass(className).isEnum();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), className);
+ return false;
+ }
+ }
+
+ /**
+ * Returns the first enum value of an enum class
+ *
+ * @param className full qualified class name
+ * @return the first enum value name found in order
+ */
+ public String getFirstEnumValue(String className) {
+
+ try {
+ Class> enumClass = ClassUtils.getClass(className);
+ Field[] declaredFields = enumClass.getDeclaredFields();
+ if (declaredFields.length > 0) {
+ return declaredFields[0].getName();
+ } else {
+ return null;
+ }
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), className);
+ return null;
+ }
+ }
+}
diff --git a/cobigen-templates/crud-java-server-app/pom.xml b/cobigen-templates/crud-java-server-app/pom.xml
index a96bb42a5f..ba577e68e5 100644
--- a/cobigen-templates/crud-java-server-app/pom.xml
+++ b/cobigen-templates/crud-java-server-app/pom.xml
@@ -10,4 +10,10 @@
${revision}
+
+
+ org.apache.commons
+ commons-lang3
+
+
\ No newline at end of file
diff --git a/cobigen-templates/crud-java-server-app/src/main/java/com/devonfw/cobigen/templates/devon4j/constants/Field.java b/cobigen-templates/crud-java-server-app/src/main/java/com/devonfw/cobigen/templates/devon4j/constants/Field.java
new file mode 100644
index 0000000000..5376daaea9
--- /dev/null
+++ b/cobigen-templates/crud-java-server-app/src/main/java/com/devonfw/cobigen/templates/devon4j/constants/Field.java
@@ -0,0 +1,48 @@
+package com.devonfw.cobigen.templates.devon4j.constants;
+
+/**
+ * Contains the used keys for the pojo field mapping
+ */
+public enum Field {
+
+ /**
+ * Name of the field
+ */
+ NAME("name"),
+ /**
+ * Type of the field
+ */
+ TYPE("type"),
+ /**
+ * Canonical Type of the field
+ */
+ CANONICAL_TYPE("canonicalType"),
+ /**
+ * The Javadoc of the field
+ */
+ JAVA_DOC("javaDoc"),
+ /**
+ * Annotations
+ */
+ ANNOTATIONS("annotations");
+
+ /**
+ * key value
+ */
+ private String value;
+
+ /**
+ * @param value of the key
+ */
+ Field(String value) {
+
+ this.value = value;
+ }
+
+ @Override
+ public String toString() {
+
+ return this.value;
+ }
+
+}
diff --git a/cobigen-templates/crud-java-server-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/DevonfwUtil.java b/cobigen-templates/crud-java-server-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/DevonfwUtil.java
new file mode 100644
index 0000000000..36e39b5e06
--- /dev/null
+++ b/cobigen-templates/crud-java-server-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/DevonfwUtil.java
@@ -0,0 +1,450 @@
+package com.devonfw.cobigen.templates.devon4j.utils;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.NodeList;
+
+import com.devonfw.cobigen.templates.devon4j.constants.Field;
+import com.sun.org.apache.xerces.internal.dom.DeferredElementNSImpl;
+
+/**
+ * A class for shared devon4j specific functions in the templates
+ *
+ */
+@SuppressWarnings("restriction")
+public class DevonfwUtil {
+
+ /**
+ * Check whether the given 'canonicalType' is a devon4j Entity, which is declared in the given 'component'
+ *
+ * @param canonicalType the type name
+ * @param component the component name
+ * @return true iff the canonicalType is a devon Entity
+ */
+ public boolean isEntityInComponent(String canonicalType, String component) {
+
+ return canonicalType.matches(String.format(".+%1$s\\.dataaccess\\.api\\.[A-Za-z0-9]+Entity(<.*)?", component));
+ }
+
+ /**
+ * Check whether the given 'canonicalType' is declared in the given 'component'
+ *
+ * @param canonicalType the type name
+ * @param component the component name
+ * @return true iff the canonicalType is inside the given component
+ */
+ public boolean isTypeInComponent(String canonicalType, String component) {
+
+ return canonicalType.matches(String.format("%1$s.[A-Za-z0-9]+(<.*)?", component));
+ }
+
+ /**
+ * Determines the ID getter for a given 'field' dependent on whether the getter should access the ID via an object
+ * reference or a direct ID getter
+ *
+ * @param field the field
+ * @param byObjectReference boolean
+ * @param component the devon4j component name
+ * @return 'get' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)} + '()' with
+ * capitalize=true
+ */
+ public String resolveIdGetter(Map field, boolean byObjectReference, String component) {
+
+ // If field comes from an UML file
+ if (field.getClass().toGenericString().contains("freemarker.ext.beans.HashAdapter")) {
+ DeferredElementNSImpl umlNode = (DeferredElementNSImpl) field;
+ return resolveIdGetter(umlNode, byObjectReference, component);
+ }
+ return "get" + resolveIdVariableNameOrSetterGetterSuffix(field, byObjectReference, true, component) + "()";
+ }
+
+ /**
+ * Determines the ID getter for a given 'field' dependent on whether the getter should access the ID via an object
+ * reference or a direct ID getter
+ *
+ * This method is used when the field parameter comes from an UML file. The name and type of the attributes must be
+ * pre-processed for later inserting them inside the HashMap.
+ *
+ * @param field the field
+ * @param byObjectReference boolean
+ * @param component the devon4j component name
+ * @return 'get' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)} + '()' with
+ * capitalize=true
+ */
+ public String resolveIdGetter(DeferredElementNSImpl field, boolean byObjectReference, String component) {
+
+ HashMap nodeHash = new HashMap<>();
+
+ // Putting the name of the attribute to the hash
+ nodeHash.put(Field.NAME.toString(), field.getAttribute("name"));
+
+ // Putting the type of the attribute to the hash
+ NodeList childs = field.getChildNodes();
+ for (int i = 0; i < childs.getLength(); i++) {
+ // Retrieve "type" tag
+ if (childs.item(i).getNodeName().equals("type")) {
+ NamedNodeMap attrs = childs.item(i).getAttributes();
+ for (int j = 0; j < attrs.getLength(); j++) {
+ Attr attribute = (Attr) attrs.item(j);
+ // Try to find the attribute that contains the type
+ if (attribute.getName().equals("xmi:idref")) {
+ nodeHash.put(Field.TYPE.toString(), attribute.getName().replace("EAJava_", ""));
+ }
+ }
+ }
+ }
+ return "get" + resolveIdVariableNameOrSetterGetterSuffix(nodeHash, byObjectReference, true, component) + "()";
+
+ }
+
+ /**
+ * Determines the ID getter for a given 'field' dependent on whether the getter should access the ID via an object
+ * reference or a direct ID getter
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldMap the field mapping
+ * @param byObjectReference boolean
+ * @param component the devon4j component name
+ * @return 'get' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)} + '()' with
+ * capitalize=true
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdGetter(Class> pojoClass, Map fieldMap, boolean byObjectReference,
+ String component) throws NoSuchFieldException, SecurityException {
+
+ return "get" + resolveIdVariableNameOrSetterGetterSuffix(pojoClass, fieldMap, byObjectReference, true, component)
+ + "()";
+ }
+
+ /**
+ * same as {@link #resolveIdGetter(Map, boolean, String)} but with byObjectReference=false and component=""
+ *
+ * @param field the field
+ * @return 'get' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map,boolean,boolean,String)} + '()' with
+ * capitalize=true
+ */
+ public String resolveIdGetter(Map field) {
+
+ return this.resolveIdGetter(field, false, "");
+ }
+
+ /**
+ * same as {@link #resolveIdGetter(Class,Map,boolean,String)} but with byObjectReference=false and component=""
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldMap the field mapping
+ * @return 'get' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map,boolean,boolean,String)} + '()' with
+ * capitalize=true
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdGetter(Class> pojoClass, Map fieldMap)
+ throws NoSuchFieldException, SecurityException {
+
+ return resolveIdGetter(pojoClass, fieldMap, false, "");
+ }
+
+ /**
+ * Determines the ID setter for a given 'field' dependent on whether the setter should access the ID via an object
+ * reference or a direct ID setter. In contrast to resolveIdGetter, this function does not generate the function
+ * parenthesis to enable parameter declaration.
+ *
+ * @param field the field
+ * @param byObjectReference boolean
+ * @param component the devon4j component name
+ * @return 'set' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)} with
+ * capitalize=true
+ */
+ public String resolveIdSetter(Map field, boolean byObjectReference, String component) {
+
+ return "set" + resolveIdVariableNameOrSetterGetterSuffix(field, byObjectReference, true, component);
+ }
+
+ /**
+ * same as {@link #resolveIdSetter(Map, boolean, String)} but with byObjectReference=false and component=""
+ *
+ * @param field the field
+ * @return 'set' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)} with
+ * capitalize=true
+ */
+ public String resolveIdSetter(Map field) {
+
+ return this.resolveIdSetter(field, false, "");
+ }
+
+ /**
+ * Determines the ID setter for a given 'field' dependent on whether the setter should access the ID via an object
+ * reference or a direct ID setter. In contrast to resolveIdGetter, this function does not generate the function
+ * parenthesis to enable parameter declaration.
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldMap the field mapping
+ * @param byObjectReference boolean
+ * @param component the devon4j component name
+ * @return 'set'+ {@link #resolveIdVariableNameOrSetterGetterSuffix(Map,boolean,boolean,String)} with capitalize=true
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdSetter(Class> pojoClass, Map fieldMap, boolean byObjectReference,
+ String component) throws NoSuchFieldException, SecurityException {
+
+ return "set" + resolveIdVariableNameOrSetterGetterSuffix(pojoClass, fieldMap, byObjectReference, true, component);
+ }
+
+ /**
+ * same as {@link #resolveIdSetter(Class,Map,boolean,String)} but with byObjectReference=false and component=""
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldMap the field mapping
+ * @return 'set' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map,boolean,boolean,String)} with capitalize=true
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdSetter(Class> pojoClass, Map fieldMap)
+ throws NoSuchFieldException, SecurityException {
+
+ return resolveIdSetter(pojoClass, fieldMap, false, "");
+ }
+
+ /**
+ * Determines the variable name for the id value of the 'field'
+ *
+ * @param field the field
+ * @return {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)}) with
+ * byObjectReference=false, capitalize=false and component=""
+ */
+ public String resolveIdVariableName(Map field) {
+
+ // the component is passed down as an empty string since byObjectReference is false and therefore the
+ // component is
+ // never touched
+ return resolveIdVariableNameOrSetterGetterSuffix(field, false, false, "");
+ }
+
+ /**
+ * Determines the variable name for the id value of the specified field in the pojo
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldMap the field mapping
+ * @return {@link #resolveIdVariableNameOrSetterGetterSuffix(Class, Map, boolean, boolean, String)}) with
+ * byObjectReference=false, capitalize=false and component=""
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdVariableName(Class> pojoClass, Map fieldMap)
+ throws NoSuchFieldException, SecurityException {
+
+ // the component is passed down as an empty string since byObjectReference is false and therefore the
+ // component is
+ // never touched
+ return resolveIdVariableNameOrSetterGetterSuffix(pojoClass, fieldMap, false, false, "");
+ }
+
+ /**
+ * Determines the ID setter/getter suffix for a given 'field' dependent on whether the setter/getter should access the
+ * ID via an object reference or a direct ID setter/getter
+ *
+ * @param field the field
+ * @param byObjectReference boolean
+ * @param capitalize if the field name should be capitalized
+ * @param component the devon4j component. Only needed if $byObjectReference is true
+ * @return idVariable name or getter/setter suffix
+ */
+ public String resolveIdVariableNameOrSetterGetterSuffix(Map field, boolean byObjectReference,
+ boolean capitalize, String component) {
+
+ String fieldName = (String) field.get(Field.NAME.toString());
+ if (capitalize) {
+ fieldName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
+ }
+ String suffix = "";
+
+ String fieldType = (String) field.get(Field.TYPE.toString());
+ String fieldCType = (String) field.get(Field.CANONICAL_TYPE.toString());
+ if (fieldType.contains("Entity")) {
+ if (fieldCType.startsWith("java.util.List") || fieldCType.startsWith("java.util.Set")) {
+ suffix = "Ids";
+ if (fieldName.endsWith("s")) {
+ // Assume trailing 's' as indicator for a plural
+ fieldName = fieldName.substring(0, fieldName.length() - 1);
+ }
+ } else {
+ suffix = "Id";
+ }
+ if (byObjectReference && isTypeInComponent(fieldCType, component)) {
+ // direct references for Entities in same component, so get id of the object reference
+ suffix = "().getId";
+ }
+ }
+
+ return fieldName + suffix;
+
+ }
+
+ /**
+ * Determines the ID setter/getter suffix for a given 'field' dependent on whether the setter/getter should access the
+ * ID via an object reference or a direct ID setter/getter
+ *
+ * @param pojoClass the {@link Class} object of the pojo
+ * @param fieldMap the field mapping
+ * @param byObjectReference boolean
+ * @param capitalize if the field name should be capitalized
+ * @param component the devon4j component. Only needed if byObjectReference is true
+ * @return idVariable name or getter/setter suffix
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdVariableNameOrSetterGetterSuffix(Class> pojoClass, Map fieldMap,
+ boolean byObjectReference, boolean capitalize, String component) throws NoSuchFieldException, SecurityException {
+
+ String resultName = (String) fieldMap.get(Field.NAME.toString());
+ if (capitalize) {
+ resultName = resultName.substring(0, 1).toUpperCase() + resultName.substring(1);
+ }
+ String suffix = "";
+ String fieldType = (String) fieldMap.get(Field.TYPE.toString());
+ String fieldName = (String) fieldMap.get(Field.NAME.toString());
+ if (fieldType.contains("Entity")) {
+ if (Collection.class.isAssignableFrom(pojoClass.getDeclaredField(fieldName).getType())) {
+ suffix = "Ids";
+ if (resultName.endsWith("s")) {
+ // Assume trailing 's' as indicator for a plural
+ resultName = resultName.substring(0, resultName.length() - 1);
+ }
+ } else {
+ suffix = "Id";
+ }
+ if (byObjectReference
+ && isEntityInComponent(pojoClass.getDeclaredField(fieldName).getType().getName(), component)) {
+ // direct references for Entities in same component, so get id of the object reference
+ suffix = "().getId";
+ }
+ }
+
+ return resultName + suffix;
+
+ }
+
+ /**
+ * Returns the argument type of the list or set from a field. If the string contains "Entity" it will remove that
+ * part. For example, if we have a List <SampleEntity> it will return "Sample"
+ *
+ * @param field the field
+ * @param pojoClass the object class of the Entity that contains the field
+ * @return fieldType argument of the list
+ * @throws SecurityException if field type could not accessed
+ * @throws NoSuchFieldException if field could not be found
+ */
+ public String getListArgumentType(Map field, Class> pojoClass)
+ throws NoSuchFieldException, SecurityException {
+
+ JavaUtil javaUtil = new JavaUtil();
+
+ String fieldType = (String) field.get(Field.TYPE.toString());
+ String fieldName = (String) field.get(Field.NAME.toString());
+
+ if (fieldType.contains("Entity")) {
+ if (javaUtil.isCollection(pojoClass, fieldName)) {
+
+ fieldType = fieldType.replace("Entity", "");
+ // Regex: Extracts the argument type of the list 'List' => type
+ String regex = "(?<=\\<).+?(?=\\>)";
+ Pattern pattern = Pattern.compile(regex);
+ Matcher regexMatcher = pattern.matcher(fieldType);
+
+ if (regexMatcher.find()) {
+ fieldType = regexMatcher.group(0);
+ }
+ }
+ }
+ return fieldType;
+
+ }
+
+ /**
+ * Converts all occurrences of devon4j Entity types in the given 'field' simple type (possibly generic) to Longs
+ *
+ * @param field the field
+ * @return the field type as String. If field type contains 'Entity' the result is Long
+ */
+ public String getSimpleEntityTypeAsLongReference(Map field) {
+
+ String fieldType = (String) field.get(Field.TYPE.toString());
+ if (fieldType.endsWith("Entity")) {
+ fieldType = fieldType.replaceAll("[^<>]+Entity", "Long");
+ }
+ return fieldType;
+ }
+
+ /**
+ * If the string last character is an 's', then it gets removed
+ *
+ * @param targetClassName string to remove plural
+ * @return string without 's'
+ */
+ public String removePlural(String targetClassName) {
+
+ if (targetClassName.charAt(targetClassName.length() - 1) == 's') {
+ targetClassName = targetClassName.substring(0, targetClassName.length() - 1);
+ }
+ return targetClassName;
+ }
+
+ /**
+ * Checks whether the operation with the given ID corresponds to any standard CRUD method name.
+ *
+ * @param operationId operation ID interpreted as method name
+ * @param entityName entity name to check standard CRUD methods for
+ * @return true
if the operation ID maps any standard CRUD method name, false
otherwise
+ */
+ public boolean isCrudOperation(String operationId, String entityName) {
+
+ if (operationId == null) {
+ return false;
+ }
+ String opIdLowerCase = operationId.toLowerCase();
+ String entityNameLowerCase = entityName.toLowerCase();
+ if (opIdLowerCase.contains(entityNameLowerCase)) {
+ return opIdLowerCase.equals("find" + entityNameLowerCase)
+ || opIdLowerCase.equals("find" + entityNameLowerCase + "Etos")
+ || opIdLowerCase.equals("delete" + entityNameLowerCase) || opIdLowerCase.equals("save" + entityNameLowerCase);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Converts the given media type to the spring Java enum value
+ *
+ * @param mediaType to be converted
+ * @return the spring enum value representing the given media type
+ */
+ public String getSpringMediaType(String mediaType) {
+
+ switch (mediaType) {
+ case "application/xml":
+ return "APPLICATION_XML_VALUE";
+ case "application / x-www-form-urlencoded":
+ return "APPLICATION_FORM_URLENCODED_VALUE";
+ case "multipart/form-data":
+ return "MULTIPART_FORM_DATA_VALUE";
+ case "text/plain":
+ return "TEXT_PLAIN_VALUE";
+ case "text/html":
+ return "TEXT_HTML_VALUE";
+ case "application/pdf":
+ return "APPLICATION_PDF_VALUE";
+ case "image/png":
+ return "IMAGE_PNG_VALUE";
+ default:
+ return "APPLICATION_JSON_VALUE";
+ }
+ }
+}
\ No newline at end of file
diff --git a/cobigen-templates/crud-java-server-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java b/cobigen-templates/crud-java-server-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java
new file mode 100644
index 0000000000..ced2f5fde2
--- /dev/null
+++ b/cobigen-templates/crud-java-server-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java
@@ -0,0 +1,464 @@
+package com.devonfw.cobigen.templates.devon4j.utils;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.commons.lang3.ClassUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Provides type operations, mainly checks and casts for Java Primitives, to be used in the templates
+ *
+ */
+public class JavaUtil {
+
+ /**
+ * Logger for this class
+ */
+ private static final Logger LOG = LoggerFactory.getLogger(JavaUtil.class);
+
+ /**
+ * The constructor.
+ */
+ public JavaUtil() {
+
+ // Empty for CobiGen to automatically instantiate it
+ }
+
+ /**
+ * Returns the Object version of a Java primitive or the input if the input isn't a java primitive
+ *
+ * @param simpleType String
+ * @return the corresponding object wrapper type simple name of the input if the input is the name of a primitive java
+ * type. The input itself if not. (e.g. "int" results in "Integer")
+ * @throws ClassNotFoundException should not occur.
+ */
+ public String boxJavaPrimitives(String simpleType) throws ClassNotFoundException {
+
+ if (equalsJavaPrimitive(simpleType)) {
+ return ClassUtils.primitiveToWrapper(ClassUtils.getClass(simpleType)).getSimpleName();
+ } else {
+ return simpleType;
+ }
+
+ }
+
+ /**
+ * Returns the simple name of the type of a field in the pojoClass. If the type is a java primitive the name of the
+ * wrapper class is returned
+ *
+ * @param pojoClass {@link Class} the class object of the pojo
+ * @param fieldName {@link String} the name of the field
+ * @return String. The simple name of the field's type. The simple name of the wrapper class in case of java
+ * primitives
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public String boxJavaPrimitives(Class> pojoClass, String fieldName) throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+
+ if (equalsJavaPrimitive(pojoClass, fieldName)) {
+ return ClassUtils.primitiveToWrapper(pojoClass.getDeclaredField(fieldName).getType()).getSimpleName();
+ } else {
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ throw new IllegalAccessError("Could not find field " + fieldName + " in class " + pojoClass);
+ } else {
+ return field.getType().getSimpleName();
+ }
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive
+ *
+ * @param simpleType the type to be checked
+ * @return true iff simpleType is a Java primitive
+ */
+ public boolean equalsJavaPrimitive(String simpleType) {
+
+ try {
+ return ClassUtils.getClass(simpleType).isPrimitive();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive or wrapper
+ *
+ * @param simpleType the type to be checked
+ * @return true iff simpleType is a Java primitive or wrapper
+ */
+ public boolean equalsJavaPrimitiveOrWrapper(String simpleType) {
+
+ try {
+ return ClassUtils.isPrimitiveOrWrapper(ClassUtils.getClass(simpleType));
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the type of the field in the pojo's class is a java primitive
+ *
+ * @param pojoClass the {@link Class} object of the pojo
+ * @param fieldName the name of the field to be checked
+ * @return true iff the field is a java primitive
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean equalsJavaPrimitive(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ return false;
+ }
+
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ return false;
+ } else {
+ return field.getType().isPrimitive();
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive or a Java primitive array
+ *
+ * @param simpleType the Type name to be checked
+ * @return true iff {@link #equalsJavaPrimitive(String)} is true or if simpleType is an array with a primitive
+ * component
+ */
+ public boolean equalsJavaPrimitiveIncludingArrays(String simpleType) {
+
+ Class> klasse;
+
+ try {
+ klasse = ClassUtils.getClass(simpleType).getComponentType();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ return equalsJavaPrimitive(simpleType) || (klasse != null && klasse.isPrimitive());
+ }
+
+ /**
+ * Checks if the given field in the pojo class is a java primitive or an array of java primitives
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldName the name of the field to be checked
+ * @return true iff {@link #equalsJavaPrimitive(Class, String)} is true or the field is an array of primitives
+ * @throws NoSuchFieldException indicating something awfully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean equalsJavaPrimitiveIncludingArrays(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ return equalsJavaPrimitive(pojoClass, fieldName) || (pojoClass.getDeclaredField(fieldName).getType().isArray()
+ && pojoClass.getDeclaredField(fieldName).getType().getComponentType().isPrimitive());
+ }
+
+ /**
+ * Returns a cast statement for a given (java primitive, variable name) pair or nothing if the type isn't a java
+ * primitive
+ *
+ * @param simpleType Java Type
+ * @param varName Variable name
+ * @return String either of the form '((Java Primitive Object Type)varName)' if simpleType is a primitive or the empty
+ * String otherwise
+ * @throws ClassNotFoundException should not occur
+ */
+ public String castJavaPrimitives(String simpleType, String varName) throws ClassNotFoundException {
+
+ if (equalsJavaPrimitive(simpleType)) {
+ return String.format("((%1$s)%2$s)", boxJavaPrimitives(simpleType), varName);
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * Returns a cast statement for a given (java primitive, variable name) pair or nothing if the type isn't a java
+ * primitive
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldName the name of the field to be casted
+ * @return if fieldName points to a primitive field then a casted statement (e.g. for an int field:
+ * '((Integer)field)') or an empty String otherwise
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public String castJavaPrimitives(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ if (equalsJavaPrimitive(pojoClass, fieldName)) {
+ return String.format("((%1$s)%2$s)", boxJavaPrimitives(pojoClass, fieldName), fieldName);
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * @param pojoClass {@link Class} the class object of the pojo
+ * @param fieldName {@link String} the name of the field
+ * @return true if the field is an instance of java.utils.Collections
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean isCollection(Class> pojoClass, String fieldName) throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ return false;
+ }
+
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ return false;
+ } else {
+ return Collection.class.isAssignableFrom(field.getType());
+ }
+
+ }
+
+ /**
+ * Returns the Ext Type to a given java type
+ *
+ * @param simpleType any java type's simple name
+ * @return corresponding Ext type
+ */
+ public String getExtType(String simpleType) {
+
+ switch (simpleType) {
+ case "short":
+ case "Short":
+ case "int":
+ case "Integer":
+ case "long":
+ case "Long":
+ return "Integer";
+ case "float":
+ case "Float":
+ case "double":
+ case "Double":
+ return "Number";
+ case "boolean":
+ case "Boolean":
+ return "Boolean";
+ case "char":
+ case "Character":
+ case "String":
+ return "String";
+ case "Date":
+ return "Date";
+ default:
+ return "Field";
+ }
+ }
+
+ /**
+ * returns the Angular5 type associated with a Java primitive
+ *
+ * @param simpleType :{@link String} the type to be parsed
+ * @return the corresponding Angular type or 'any' otherwise
+ */
+ public String getAngularType(String simpleType) {
+
+ switch (simpleType) {
+ case "boolean":
+ return "boolean";
+ case "Boolean":
+ return "boolean";
+ case "short":
+ return "number";
+ case "Short":
+ return "number";
+ case "int":
+ return "number";
+ case "Integer":
+ return "number";
+ case "long":
+ return "number";
+ case "Long":
+ return "number";
+ case "float":
+ return "number";
+ case "Float":
+ return "number";
+ case "double":
+ return "number";
+ case "Double":
+ return "number";
+ case "char":
+ return "string";
+ case "Character":
+ return "string";
+ case "String":
+ return "string";
+ case "byte":
+ return "number";
+ default:
+ return "any";
+ }
+ }
+
+ /**
+ * returns the class name of the return type of a specific method.
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName {@link String} the name of the method
+ * @return the class name of the return type of the specified method
+ * @throws SecurityException If no method of the given name can be found
+ * @throws NoSuchMethodException If no method of the given name can be found
+ */
+ public String getReturnType(Class> pojoClass, String methodName) throws NoSuchMethodException, SecurityException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+ String s = "-";
+ Method method = findMethod(pojoClass, methodName);
+ if (method != null && !method.getReturnType().equals(Void.TYPE)) {
+ s = method.getReturnType().toString();
+ s = s.substring(s.lastIndexOf('.') + 1, s.length());
+ }
+ return s;
+ }
+
+ /**
+ *
+ * This methods returns the return type of the method in the given pojoClass which are annotated with the parameter
+ * annotatedClass
+ *
+ * @param pojoClass - The class in which to find if it has methods with annotatedClass
+ * @param annotatedClassName - The annotation which needs to be found
+ * @return Return type of the method annotated with the given annotation, else "null"
+ * @throws ClassNotFoundException if the annotated class name could not be found in the class path
+ */
+ @SuppressWarnings("unchecked")
+ public String getReturnTypeOfMethodAnnotatedWith(Class> pojoClass, String annotatedClassName)
+ throws ClassNotFoundException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+
+ Method[] methods = pojoClass.getDeclaredMethods();
+ for (Method method : methods) {
+ if (!method.getName().startsWith("get")) {
+ continue;
+ }
+ for (Annotation a : method.getAnnotations()) {
+ // better if (method.isAnnotationPresent(classObj)) {, but postponed as of different class
+ // loaders of a.getClass() and pojoClass.getClass()
+ if (a.getClass().getCanonicalName().equals(annotatedClassName)) {
+ return method.getReturnType().getSimpleName();
+ }
+ }
+ }
+ return "null";
+ }
+
+ /**
+ * returns the HTTP request type corresponding to an annotation type
+ *
+ * @param annotations The annotation to get the type name of
+ * @return the HTTP request type name of the selected annotation
+ */
+ public String getRequestType(Map annotations) {
+
+ if (annotations.containsKey("javax_ws_rs_GET")) {
+ return "GET";
+ } else if (annotations.containsKey("javax_ws_rs_PUT")) {
+ return "PUT";
+ } else if (annotations.containsKey("javax_ws_rs_POST")) {
+ return "POST";
+ } else if (annotations.containsKey("javax_ws_rs_DELETE")) {
+ return "DELETE";
+ } else if (annotations.containsKey("javax_ws_rs_PATCH")) {
+ return "PATCH";
+ } else {
+ return "-";
+ }
+ }
+
+ /**
+ * Helper method to find a class's specific method
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName The name of the method to be found
+ * @return The method object of the method to be found, null if it wasn't found
+ */
+ private Method findMethod(Class> pojoClass, String methodName) {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+ for (Method m : pojoClass.getMethods()) {
+ if (m.getName().equals(methodName)) {
+ return m;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Checks whether the class given by the full qualified name is an enum
+ *
+ * @param className full qualified class name
+ * @return true
if the class is an enum, false
otherwise
+ */
+ public boolean isEnum(String className) {
+
+ try {
+ return ClassUtils.getClass(className).isEnum();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), className);
+ return false;
+ }
+ }
+
+ /**
+ * Returns the first enum value of an enum class
+ *
+ * @param className full qualified class name
+ * @return the first enum value name found in order
+ */
+ public String getFirstEnumValue(String className) {
+
+ try {
+ Class> enumClass = ClassUtils.getClass(className);
+ Field[] declaredFields = enumClass.getDeclaredFields();
+ if (declaredFields.length > 0) {
+ return declaredFields[0].getName();
+ } else {
+ return null;
+ }
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), className);
+ return null;
+ }
+ }
+}
diff --git a/cobigen-templates/crud-ngrx-client-app/pom.xml b/cobigen-templates/crud-ngrx-client-app/pom.xml
index 7268b65f2f..b5287e0cd5 100644
--- a/cobigen-templates/crud-ngrx-client-app/pom.xml
+++ b/cobigen-templates/crud-ngrx-client-app/pom.xml
@@ -10,4 +10,10 @@
${revision}
+
+
+ org.apache.commons
+ commons-lang3
+
+
\ No newline at end of file
diff --git a/cobigen-templates/crud-ngrx-client-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java b/cobigen-templates/crud-ngrx-client-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java
new file mode 100644
index 0000000000..2d4025071d
--- /dev/null
+++ b/cobigen-templates/crud-ngrx-client-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java
@@ -0,0 +1,464 @@
+package com.devonfw.cobigen.templates.devon4j.utils;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.commons.lang3.ClassUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Provides type operations, mainly checks and casts for Java Primitives, to be used in the templates
+ *
+ */
+public class JavaUtil {
+
+ /**
+ * Logger for this class
+ */
+ private static final Logger LOG = LoggerFactory.getLogger(JavaUtil.class);
+
+ /**
+ * The constructor.
+ */
+ public JavaUtil() {
+
+ // Empty for CobiGen to automatically instantiate it
+ }
+
+ /**
+ * Returns the Object version of a Java primitive or the input if the input isn't a java primitive
+ *
+ * @param simpleType String
+ * @return the corresponding object wrapper type simple name of the input if the input is the name of a primitive java
+ * type. The input itself if not. (e.g. "int" results in "Integer")
+ * @throws ClassNotFoundException should not occur.
+ */
+ public String boxJavaPrimitives(String simpleType) throws ClassNotFoundException {
+
+ if (equalsJavaPrimitive(simpleType)) {
+ return ClassUtils.primitiveToWrapper(ClassUtils.getClass(simpleType)).getSimpleName();
+ } else {
+ return simpleType;
+ }
+
+ }
+
+ /**
+ * Returns the simple name of the type of a field in the pojoClass. If the type is a java primitive the name of the
+ * wrapper class is returned
+ *
+ * @param pojoClass {@link Class} the class object of the pojo
+ * @param fieldName {@link String} the name of the field
+ * @return String. The simple name of the field's type. The simple name of the wrapper class in case of java
+ * primitives
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public String boxJavaPrimitives(Class> pojoClass, String fieldName) throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+
+ if (equalsJavaPrimitive(pojoClass, fieldName)) {
+ return ClassUtils.primitiveToWrapper(pojoClass.getDeclaredField(fieldName).getType()).getSimpleName();
+ } else {
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ throw new IllegalAccessError("Could not find field " + fieldName + " in class " + pojoClass);
+ } else {
+ return field.getType().getSimpleName();
+ }
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive
+ *
+ * @param simpleType the type to be checked
+ * @return true iff simpleType is a Java primitive
+ */
+ public boolean equalsJavaPrimitive(String simpleType) {
+
+ try {
+ return ClassUtils.getClass(simpleType).isPrimitive();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive or wrapper
+ *
+ * @param simpleType the type to be checked
+ * @return true iff simpleType is a Java primitive or wrapper
+ */
+ public boolean equalsJavaPrimitiveOrWrapper(String simpleType) {
+
+ try {
+ return ClassUtils.isPrimitiveOrWrapper(ClassUtils.getClass(simpleType));
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the type of the field in the pojo's class is a java primitive
+ *
+ * @param pojoClass the {@link Class} object of the pojo
+ * @param fieldName the name of the field to be checked
+ * @return true iff the field is a java primitive
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean equalsJavaPrimitive(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ return false;
+ }
+
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ return false;
+ } else {
+ return field.getType().isPrimitive();
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive or a Java primitive array
+ *
+ * @param simpleType the Type name to be checked
+ * @return true iff {@link #equalsJavaPrimitive(String)} is true or if simpleType is an array with a primitive
+ * component
+ */
+ public boolean equalsJavaPrimitiveIncludingArrays(String simpleType) {
+
+ Class> klasse;
+
+ try {
+ klasse = ClassUtils.getClass(simpleType).getComponentType();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ return equalsJavaPrimitive(simpleType) || (klasse != null && klasse.isPrimitive());
+ }
+
+ /**
+ * Checks if the given field in the pojo class is a java primitive or an array of java primitives
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldName the name of the field to be checked
+ * @return true iff {@link #equalsJavaPrimitive(Class, String)} is true or the field is an array of primitives
+ * @throws NoSuchFieldException indicating something awfully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean equalsJavaPrimitiveIncludingArrays(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ return equalsJavaPrimitive(pojoClass, fieldName) || (pojoClass.getDeclaredField(fieldName).getType().isArray()
+ && pojoClass.getDeclaredField(fieldName).getType().getComponentType().isPrimitive());
+ }
+
+ /**
+ * Returns a cast statement for a given (java primitive, variable name) pair or nothing if the type isn't a java
+ * primitive
+ *
+ * @param simpleType Java Type
+ * @param varName Variable name
+ * @return String either of the form '((Java Primitive Object Type)varName)' if simpleType is a primitive or the empty
+ * String otherwise
+ * @throws ClassNotFoundException should not occur
+ */
+ public String castJavaPrimitives(String simpleType, String varName) throws ClassNotFoundException {
+
+ if (equalsJavaPrimitive(simpleType)) {
+ return String.format("((%1$s)%2$s)", boxJavaPrimitives(simpleType), varName);
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * Returns a cast statement for a given (java primitive, variable name) pair or nothing if the type isn't a java
+ * primitive
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldName the name of the field to be casted
+ * @return if fieldName points to a primitive field then a casted statement (e.g. for an int field:
+ * '((Integer)field)') or an empty String otherwise
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public String castJavaPrimitives(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ if (equalsJavaPrimitive(pojoClass, fieldName)) {
+ return String.format("((%1$s)%2$s)", boxJavaPrimitives(pojoClass, fieldName), fieldName);
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * @param pojoClass {@link Class} the class object of the pojo
+ * @param fieldName {@link String} the name of the field
+ * @return true if the field is an instance of java.utils.Collections
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean isCollection(Class> pojoClass, String fieldName) throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ return false;
+ }
+
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ return false;
+ } else {
+ return Collection.class.isAssignableFrom(field.getType());
+ }
+
+ }
+
+ /**
+ * Returns the Ext Type to a given java type
+ *
+ * @param simpleType any java type's simple name
+ * @return corresponding Ext type
+ */
+ public String getExtType(String simpleType) {
+
+ switch (simpleType) {
+ case "short":
+ case "Short":
+ case "int":
+ case "Integer":
+ case "long":
+ case "Long":
+ return "Integer";
+ case "float":
+ case "Float":
+ case "double":
+ case "Double":
+ return "Number";
+ case "boolean":
+ case "Boolean":
+ return "Boolean";
+ case "char":
+ case "Character":
+ case "String":
+ return "String";
+ case "Date":
+ return "Date";
+ default:
+ return "Field";
+ }
+ }
+
+ /**
+ * returns the Angular5 type associated with a Java primitive
+ *
+ * @param simpleType :{@link String} the type to be parsed
+ * @return the corresponding Angular type or 'any' otherwise
+ */
+ public String getAngularType(String simpleType) {
+
+ switch (simpleType) {
+ case "boolean":
+ return "boolean";
+ case "Boolean":
+ return "boolean";
+ case "short":
+ return "number";
+ case "Short":
+ return "number";
+ case "int":
+ return "number";
+ case "Integer":
+ return "number";
+ case "long":
+ return "number";
+ case "Long":
+ return "number";
+ case "float":
+ return "number";
+ case "Float":
+ return "number";
+ case "double":
+ return "number";
+ case "Double":
+ return "number";
+ case "char":
+ return "string";
+ case "Character":
+ return "string";
+ case "String":
+ return "string";
+ case "byte":
+ return "number";
+ default:
+ return "any";
+ }
+ }
+
+ /**
+ * returns the class name of the return type of a specific method.
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName {@link String} the name of the method
+ * @return the class name of the return type of the specified method
+ * @throws SecurityException If no method of the given name can be found
+ * @throws NoSuchMethodException If no method of the given name can be found
+ */
+ public String getReturnType(Class> pojoClass, String methodName) throws NoSuchMethodException, SecurityException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+ String s = "-";
+ Method method = findMethod(pojoClass, methodName);
+ if (method != null && !method.getReturnType().equals(Void.TYPE)) {
+ s = method.getReturnType().toString();
+ s = s.substring(s.lastIndexOf('.') + 1, s.length());
+ }
+ return s;
+ }
+
+ /**
+ *
+ * This methods returns the return type of the method in the given pojoClass which are annotated with the parameter
+ * annotatedClass
+ *
+ * @param pojoClass - The class in which to find if it has methods with annotatedClass
+ * @param annotatedClassName - The annotation which needs to be found
+ * @return Return type of the method annotated with the given annotation, else "null"
+ * @throws ClassNotFoundException if the annotated class name could not be found in the class path
+ */
+ @SuppressWarnings("unchecked")
+ public String getReturnTypeOfMethodAnnotatedWith(Class> pojoClass, String annotatedClassName)
+ throws ClassNotFoundException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+
+ Method[] methods = pojoClass.getDeclaredMethods();
+ for (Method method : methods) {
+ if (!method.getName().startsWith("get")) {
+ continue;
+ }
+ for (Annotation a : method.getAnnotations()) {
+ // better if (method.isAnnotationPresent(classObj)) {, but postponed as of different class
+ // loaders of a.getClass() and pojoClass.getClass()
+ if (a.getClass().getCanonicalName().equals(annotatedClassName)) {
+ return method.getReturnType().getSimpleName();
+ }
+ }
+ }
+ return "null";
+ }
+
+ /**
+ * returns the HTTP request type corresponding to an annotation type
+ *
+ * @param annotations The annotation to get the type name of
+ * @return the HTTP request type name of the selected annotation
+ */
+ public String getRequestType(Map annotations) {
+
+ if (annotations.containsKey("javax_ws_rs_GET")) {
+ return "GET";
+ } else if (annotations.containsKey("javax_ws_rs_PUT")) {
+ return "PUT";
+ } else if (annotations.containsKey("javax_ws_rs_POST")) {
+ return "POST";
+ } else if (annotations.containsKey("javax_ws_rs_DELETE")) {
+ return "DELETE";
+ } else if (annotations.containsKey("javax_ws_rs_PATCH")) {
+ return "PATCH";
+ } else {
+ return "-";
+ }
+ }
+
+ /**
+ * Helper method to find a class's specific method
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName The name of the method to be found
+ * @return The method object of the method to be found, null if it wasn't found
+ */
+ private Method findMethod(Class> pojoClass, String methodName) {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+ for (Method m : pojoClass.getMethods()) {
+ if (m.getName().equals(methodName)) {
+ return m;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Checks whether the class given by the full qualified name is an enum
+ *
+ * @param className full qualified class name
+ * @return true
if the class is an enum, false
otherwise
+ */
+ public boolean isEnum(String className) {
+
+ try {
+ return ClassUtils.getClass(className).isEnum();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), className);
+ return false;
+ }
+ }
+
+ /**
+ * Returns the first enum value of an enum class
+ *
+ * @param className full qualified class name
+ * @return the first enum value name found in order
+ */
+ public String getFirstEnumValue(String className) {
+
+ try {
+ Class> enumClass = ClassUtils.getClass(className);
+ Field[] declaredFields = enumClass.getDeclaredFields();
+ if (declaredFields.length > 0) {
+ return declaredFields[0].getName();
+ } else {
+ return null;
+ }
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), className);
+ return null;
+ }
+ }
+}
diff --git a/cobigen-templates/crud-openapi-angular-client-app/pom.xml b/cobigen-templates/crud-openapi-angular-client-app/pom.xml
index 0b768bd5c8..f9f6d93770 100644
--- a/cobigen-templates/crud-openapi-angular-client-app/pom.xml
+++ b/cobigen-templates/crud-openapi-angular-client-app/pom.xml
@@ -10,4 +10,10 @@
${revision}
+
+
+ org.apache.commons
+ commons-lang3
+
+
\ No newline at end of file
diff --git a/cobigen-templates/crud-openapi-angular-client-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java b/cobigen-templates/crud-openapi-angular-client-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java
new file mode 100644
index 0000000000..ced2f5fde2
--- /dev/null
+++ b/cobigen-templates/crud-openapi-angular-client-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java
@@ -0,0 +1,464 @@
+package com.devonfw.cobigen.templates.devon4j.utils;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.commons.lang3.ClassUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Provides type operations, mainly checks and casts for Java Primitives, to be used in the templates
+ *
+ */
+public class JavaUtil {
+
+ /**
+ * Logger for this class
+ */
+ private static final Logger LOG = LoggerFactory.getLogger(JavaUtil.class);
+
+ /**
+ * The constructor.
+ */
+ public JavaUtil() {
+
+ // Empty for CobiGen to automatically instantiate it
+ }
+
+ /**
+ * Returns the Object version of a Java primitive or the input if the input isn't a java primitive
+ *
+ * @param simpleType String
+ * @return the corresponding object wrapper type simple name of the input if the input is the name of a primitive java
+ * type. The input itself if not. (e.g. "int" results in "Integer")
+ * @throws ClassNotFoundException should not occur.
+ */
+ public String boxJavaPrimitives(String simpleType) throws ClassNotFoundException {
+
+ if (equalsJavaPrimitive(simpleType)) {
+ return ClassUtils.primitiveToWrapper(ClassUtils.getClass(simpleType)).getSimpleName();
+ } else {
+ return simpleType;
+ }
+
+ }
+
+ /**
+ * Returns the simple name of the type of a field in the pojoClass. If the type is a java primitive the name of the
+ * wrapper class is returned
+ *
+ * @param pojoClass {@link Class} the class object of the pojo
+ * @param fieldName {@link String} the name of the field
+ * @return String. The simple name of the field's type. The simple name of the wrapper class in case of java
+ * primitives
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public String boxJavaPrimitives(Class> pojoClass, String fieldName) throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+
+ if (equalsJavaPrimitive(pojoClass, fieldName)) {
+ return ClassUtils.primitiveToWrapper(pojoClass.getDeclaredField(fieldName).getType()).getSimpleName();
+ } else {
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ throw new IllegalAccessError("Could not find field " + fieldName + " in class " + pojoClass);
+ } else {
+ return field.getType().getSimpleName();
+ }
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive
+ *
+ * @param simpleType the type to be checked
+ * @return true iff simpleType is a Java primitive
+ */
+ public boolean equalsJavaPrimitive(String simpleType) {
+
+ try {
+ return ClassUtils.getClass(simpleType).isPrimitive();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive or wrapper
+ *
+ * @param simpleType the type to be checked
+ * @return true iff simpleType is a Java primitive or wrapper
+ */
+ public boolean equalsJavaPrimitiveOrWrapper(String simpleType) {
+
+ try {
+ return ClassUtils.isPrimitiveOrWrapper(ClassUtils.getClass(simpleType));
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the type of the field in the pojo's class is a java primitive
+ *
+ * @param pojoClass the {@link Class} object of the pojo
+ * @param fieldName the name of the field to be checked
+ * @return true iff the field is a java primitive
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean equalsJavaPrimitive(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ return false;
+ }
+
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ return false;
+ } else {
+ return field.getType().isPrimitive();
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive or a Java primitive array
+ *
+ * @param simpleType the Type name to be checked
+ * @return true iff {@link #equalsJavaPrimitive(String)} is true or if simpleType is an array with a primitive
+ * component
+ */
+ public boolean equalsJavaPrimitiveIncludingArrays(String simpleType) {
+
+ Class> klasse;
+
+ try {
+ klasse = ClassUtils.getClass(simpleType).getComponentType();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ return equalsJavaPrimitive(simpleType) || (klasse != null && klasse.isPrimitive());
+ }
+
+ /**
+ * Checks if the given field in the pojo class is a java primitive or an array of java primitives
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldName the name of the field to be checked
+ * @return true iff {@link #equalsJavaPrimitive(Class, String)} is true or the field is an array of primitives
+ * @throws NoSuchFieldException indicating something awfully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean equalsJavaPrimitiveIncludingArrays(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ return equalsJavaPrimitive(pojoClass, fieldName) || (pojoClass.getDeclaredField(fieldName).getType().isArray()
+ && pojoClass.getDeclaredField(fieldName).getType().getComponentType().isPrimitive());
+ }
+
+ /**
+ * Returns a cast statement for a given (java primitive, variable name) pair or nothing if the type isn't a java
+ * primitive
+ *
+ * @param simpleType Java Type
+ * @param varName Variable name
+ * @return String either of the form '((Java Primitive Object Type)varName)' if simpleType is a primitive or the empty
+ * String otherwise
+ * @throws ClassNotFoundException should not occur
+ */
+ public String castJavaPrimitives(String simpleType, String varName) throws ClassNotFoundException {
+
+ if (equalsJavaPrimitive(simpleType)) {
+ return String.format("((%1$s)%2$s)", boxJavaPrimitives(simpleType), varName);
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * Returns a cast statement for a given (java primitive, variable name) pair or nothing if the type isn't a java
+ * primitive
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldName the name of the field to be casted
+ * @return if fieldName points to a primitive field then a casted statement (e.g. for an int field:
+ * '((Integer)field)') or an empty String otherwise
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public String castJavaPrimitives(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ if (equalsJavaPrimitive(pojoClass, fieldName)) {
+ return String.format("((%1$s)%2$s)", boxJavaPrimitives(pojoClass, fieldName), fieldName);
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * @param pojoClass {@link Class} the class object of the pojo
+ * @param fieldName {@link String} the name of the field
+ * @return true if the field is an instance of java.utils.Collections
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean isCollection(Class> pojoClass, String fieldName) throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ return false;
+ }
+
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ return false;
+ } else {
+ return Collection.class.isAssignableFrom(field.getType());
+ }
+
+ }
+
+ /**
+ * Returns the Ext Type to a given java type
+ *
+ * @param simpleType any java type's simple name
+ * @return corresponding Ext type
+ */
+ public String getExtType(String simpleType) {
+
+ switch (simpleType) {
+ case "short":
+ case "Short":
+ case "int":
+ case "Integer":
+ case "long":
+ case "Long":
+ return "Integer";
+ case "float":
+ case "Float":
+ case "double":
+ case "Double":
+ return "Number";
+ case "boolean":
+ case "Boolean":
+ return "Boolean";
+ case "char":
+ case "Character":
+ case "String":
+ return "String";
+ case "Date":
+ return "Date";
+ default:
+ return "Field";
+ }
+ }
+
+ /**
+ * returns the Angular5 type associated with a Java primitive
+ *
+ * @param simpleType :{@link String} the type to be parsed
+ * @return the corresponding Angular type or 'any' otherwise
+ */
+ public String getAngularType(String simpleType) {
+
+ switch (simpleType) {
+ case "boolean":
+ return "boolean";
+ case "Boolean":
+ return "boolean";
+ case "short":
+ return "number";
+ case "Short":
+ return "number";
+ case "int":
+ return "number";
+ case "Integer":
+ return "number";
+ case "long":
+ return "number";
+ case "Long":
+ return "number";
+ case "float":
+ return "number";
+ case "Float":
+ return "number";
+ case "double":
+ return "number";
+ case "Double":
+ return "number";
+ case "char":
+ return "string";
+ case "Character":
+ return "string";
+ case "String":
+ return "string";
+ case "byte":
+ return "number";
+ default:
+ return "any";
+ }
+ }
+
+ /**
+ * returns the class name of the return type of a specific method.
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName {@link String} the name of the method
+ * @return the class name of the return type of the specified method
+ * @throws SecurityException If no method of the given name can be found
+ * @throws NoSuchMethodException If no method of the given name can be found
+ */
+ public String getReturnType(Class> pojoClass, String methodName) throws NoSuchMethodException, SecurityException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+ String s = "-";
+ Method method = findMethod(pojoClass, methodName);
+ if (method != null && !method.getReturnType().equals(Void.TYPE)) {
+ s = method.getReturnType().toString();
+ s = s.substring(s.lastIndexOf('.') + 1, s.length());
+ }
+ return s;
+ }
+
+ /**
+ *
+ * This methods returns the return type of the method in the given pojoClass which are annotated with the parameter
+ * annotatedClass
+ *
+ * @param pojoClass - The class in which to find if it has methods with annotatedClass
+ * @param annotatedClassName - The annotation which needs to be found
+ * @return Return type of the method annotated with the given annotation, else "null"
+ * @throws ClassNotFoundException if the annotated class name could not be found in the class path
+ */
+ @SuppressWarnings("unchecked")
+ public String getReturnTypeOfMethodAnnotatedWith(Class> pojoClass, String annotatedClassName)
+ throws ClassNotFoundException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+
+ Method[] methods = pojoClass.getDeclaredMethods();
+ for (Method method : methods) {
+ if (!method.getName().startsWith("get")) {
+ continue;
+ }
+ for (Annotation a : method.getAnnotations()) {
+ // better if (method.isAnnotationPresent(classObj)) {, but postponed as of different class
+ // loaders of a.getClass() and pojoClass.getClass()
+ if (a.getClass().getCanonicalName().equals(annotatedClassName)) {
+ return method.getReturnType().getSimpleName();
+ }
+ }
+ }
+ return "null";
+ }
+
+ /**
+ * returns the HTTP request type corresponding to an annotation type
+ *
+ * @param annotations The annotation to get the type name of
+ * @return the HTTP request type name of the selected annotation
+ */
+ public String getRequestType(Map annotations) {
+
+ if (annotations.containsKey("javax_ws_rs_GET")) {
+ return "GET";
+ } else if (annotations.containsKey("javax_ws_rs_PUT")) {
+ return "PUT";
+ } else if (annotations.containsKey("javax_ws_rs_POST")) {
+ return "POST";
+ } else if (annotations.containsKey("javax_ws_rs_DELETE")) {
+ return "DELETE";
+ } else if (annotations.containsKey("javax_ws_rs_PATCH")) {
+ return "PATCH";
+ } else {
+ return "-";
+ }
+ }
+
+ /**
+ * Helper method to find a class's specific method
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName The name of the method to be found
+ * @return The method object of the method to be found, null if it wasn't found
+ */
+ private Method findMethod(Class> pojoClass, String methodName) {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+ for (Method m : pojoClass.getMethods()) {
+ if (m.getName().equals(methodName)) {
+ return m;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Checks whether the class given by the full qualified name is an enum
+ *
+ * @param className full qualified class name
+ * @return true
if the class is an enum, false
otherwise
+ */
+ public boolean isEnum(String className) {
+
+ try {
+ return ClassUtils.getClass(className).isEnum();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), className);
+ return false;
+ }
+ }
+
+ /**
+ * Returns the first enum value of an enum class
+ *
+ * @param className full qualified class name
+ * @return the first enum value name found in order
+ */
+ public String getFirstEnumValue(String className) {
+
+ try {
+ Class> enumClass = ClassUtils.getClass(className);
+ Field[] declaredFields = enumClass.getDeclaredFields();
+ if (declaredFields.length > 0) {
+ return declaredFields[0].getName();
+ } else {
+ return null;
+ }
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), className);
+ return null;
+ }
+ }
+}
diff --git a/cobigen-templates/crud-openapi-angular-client-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/OpenApiUtil.java b/cobigen-templates/crud-openapi-angular-client-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/OpenApiUtil.java
new file mode 100644
index 0000000000..a93288f45a
--- /dev/null
+++ b/cobigen-templates/crud-openapi-angular-client-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/OpenApiUtil.java
@@ -0,0 +1,255 @@
+package com.devonfw.cobigen.templates.devon4j.utils;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+
+/** Utils on OpenAPI template model */
+public class OpenApiUtil {
+
+ /**
+ * Prints javax validation constraints from an OpenAPI model
+ *
+ * @param constraints OpenAPI model constraints
+ * @return the list of supported annotations in Java syntax
+ */
+ public String printJavaConstraints(Map constraints) {
+
+ String consts = "";
+ if (constraints.get("maximum") != null) {
+ consts = consts + "@Max(" + constraints.get("maximum") + ")";
+ }
+ if (constraints.get("minimum") != null) {
+ consts = consts + "@Min(" + constraints.get("minimum") + ")";
+ }
+ if (constraints.get("maxLength") != null) {
+ consts = consts + "@Size(max=" + constraints.get("maxLength");
+ if (constraints.get("minLength") != null) {
+ consts = consts + ", min=" + constraints.get("minLength");
+ }
+ consts = consts + ")";
+ } else {
+ if (constraints.get("minLength") != null) {
+ consts = consts + "@Size(min=" + constraints.get("minLength");
+ if (constraints.get("maxLength") != null) {
+ consts = consts + ", max=" + constraints.get("maxLength");
+ }
+ consts = consts + ")";
+ }
+ }
+ return consts;
+ }
+
+ /**
+ * Prints the return type of a response based on the OpenAPI model
+ *
+ * @param response the OpenAPI model of a response
+ * @return simple type of the response return type in Java syntax
+ */
+ public String printJavaServiceResponseReturnType(Map response) {
+
+ String returnType = toJavaType(response, false);
+ if ((boolean) response.get("isVoid")) {
+ return "void";
+ }
+ if ((boolean) response.get("isArray")) {
+ if ((boolean) response.get("isEntity")) {
+ if (returnType.contains("Entity")) {
+ return "List<" + returnType + ">";
+ } else {
+ return "List<" + returnType + "Entity>";
+ }
+ } else {
+ return "List<" + returnType + ">";
+ }
+ } else if ((boolean) response.get("isPaginated")) {
+ if ((boolean) response.get("isEntity")) {
+ if (returnType.contains("Entity")) {
+ return "Page<" + returnType + ">";
+ } else {
+ return "Page<" + returnType + "Entity>";
+ }
+ } else {
+ return "Page<" + returnType + ">";
+ }
+ } else {
+ return returnType;
+ }
+ }
+
+ /**
+ * Returns the Java type corresponding to the OpenAPI type definition. If the type could not be matched, Object will
+ * be returned.
+ *
+ * @param parameter OpenAPI model of a parameter
+ * @param simpleType if a Java simple type should be returned if possible
+ * @return the Java type
+ */
+ public String toJavaType(Map parameter, boolean simpleType) {
+
+ String typeConverted = null;
+ String format = (String) parameter.get("format");
+ String type = (String) parameter.get("type");
+ boolean isCollection = false;
+ if (parameter.get("isCollection") != null) {
+ isCollection = (boolean) parameter.get("isCollection");
+ }
+
+ boolean isEntity = (boolean) parameter.get("isEntity");
+
+ if (type != null) {
+ switch (type.toLowerCase()) {
+ case "integer":
+ if (format != null) {
+ switch (format) {
+ case "int32":
+ typeConverted = simpleType ? "int" : "Integer";
+ break;
+ case "int64":
+ typeConverted = simpleType ? "long" : "Long";
+ break;
+ default:
+ typeConverted = BigInteger.class.getSimpleName();
+ break;
+ }
+ } else {
+ typeConverted = BigInteger.class.getSimpleName();
+ }
+ break;
+ case "number":
+ if (format != null) {
+ switch (format) {
+ case "float":
+ typeConverted = simpleType ? "float" : "Float";
+ break;
+ case "double":
+ typeConverted = simpleType ? "double" : "Double";
+ break;
+ default:
+ typeConverted = BigDecimal.class.getSimpleName();
+ break;
+ }
+ } else {
+ typeConverted = BigDecimal.class.getSimpleName();
+ }
+ break;
+ case "string":
+ if (format != null) {
+ switch (format) {
+ case "date":
+ typeConverted = LocalDate.class.getSimpleName();
+ break;
+ case "date-time":
+ typeConverted = Instant.class.getSimpleName();
+ break;
+ case "binary":
+ typeConverted = simpleType ? "float" : "Float";
+ break;
+ case "email":
+ case "password":
+ typeConverted = String.class.getSimpleName();
+ break;
+ default:
+ typeConverted = "String";
+ break;
+ }
+ } else {
+ typeConverted = "String";
+ }
+ break;
+ case "boolean":
+ typeConverted = simpleType ? "boolean" : "Boolean";
+ break;
+ default:
+ typeConverted = "void";
+ break;
+ }
+ } else {
+ typeConverted = "void";
+ }
+
+ if (isCollection) {
+ if (isEntity) {
+ return "List<" + parameter.get("type") + ">";
+ } else {
+ return "List<" + typeConverted + ">";
+ }
+ } else if (isEntity) {
+ return (String) parameter.get("type");
+ }
+ return typeConverted;
+ }
+
+ /**
+ * Returns the TypeScript type corresponding to the OpenAPI type definition. If the type could not be matched, the
+ * same value will be returned.
+ *
+ * @param parameter OpenAPI model of a parameter
+ * @return the Java type
+ */
+ // getOaspTypeFromOpenAPI
+ public String toTypeScriptType(Map parameter) {
+
+ String typeConverted = null;
+ String type = (String) parameter.get("type");
+ boolean isCollection = false;
+ if (parameter.get("isCollection") != null) {
+ isCollection = (boolean) parameter.get("isCollection");
+ }
+
+ boolean isEntity = (boolean) parameter.get("isEntity");
+
+ if (type != null) {
+ switch (type.toLowerCase()) {
+ case "integer":
+ typeConverted = "number";
+ break;
+ default:
+ typeConverted = type;
+ break;
+ }
+ } else {
+ typeConverted = "undefined";
+ }
+
+ if (isCollection) {
+ if (isEntity) {
+ return parameter.get("type") + "[]";
+ } else {
+ return typeConverted + "[]";
+ }
+ } else if (isEntity) {
+ return (String) parameter.get("type");
+ }
+ return typeConverted;
+ }
+
+ /**
+ * Prints the service operation name based on the operationId or generates one based on the servicePath while printing
+ * a comment how to get better service names.
+ *
+ * @param operation operation Model of the OpenAPI model
+ * @param servicePath service path of the
+ * @return the service method name
+ */
+ public String printServiceOperationName(Map operation, String servicePath) {
+
+ String operationId = (String) operation.get("operationId");
+ if (StringUtils.isEmpty(operationId)) {
+ String[] split = servicePath.split("/");
+ String lastSegment;
+ if (!split[split.length - 1].isEmpty()) {
+ lastSegment = split[split.length - 1];
+ } else {
+ lastSegment = split[split.length - 2];
+ }
+ return ((String) operation.get("type")) + lastSegment;
+ } else {
+ return operationId;
+ }
+ }
+}
diff --git a/cobigen-templates/crud-openapi-ionic-client-app/pom.xml b/cobigen-templates/crud-openapi-ionic-client-app/pom.xml
index 2b7cfa971a..fbfd00fd3f 100644
--- a/cobigen-templates/crud-openapi-ionic-client-app/pom.xml
+++ b/cobigen-templates/crud-openapi-ionic-client-app/pom.xml
@@ -10,4 +10,10 @@
${revision}
+
+
+ org.apache.commons
+ commons-lang3
+
+
\ No newline at end of file
diff --git a/cobigen-templates/crud-openapi-ionic-client-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java b/cobigen-templates/crud-openapi-ionic-client-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java
new file mode 100644
index 0000000000..ced2f5fde2
--- /dev/null
+++ b/cobigen-templates/crud-openapi-ionic-client-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java
@@ -0,0 +1,464 @@
+package com.devonfw.cobigen.templates.devon4j.utils;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.commons.lang3.ClassUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Provides type operations, mainly checks and casts for Java Primitives, to be used in the templates
+ *
+ */
+public class JavaUtil {
+
+ /**
+ * Logger for this class
+ */
+ private static final Logger LOG = LoggerFactory.getLogger(JavaUtil.class);
+
+ /**
+ * The constructor.
+ */
+ public JavaUtil() {
+
+ // Empty for CobiGen to automatically instantiate it
+ }
+
+ /**
+ * Returns the Object version of a Java primitive or the input if the input isn't a java primitive
+ *
+ * @param simpleType String
+ * @return the corresponding object wrapper type simple name of the input if the input is the name of a primitive java
+ * type. The input itself if not. (e.g. "int" results in "Integer")
+ * @throws ClassNotFoundException should not occur.
+ */
+ public String boxJavaPrimitives(String simpleType) throws ClassNotFoundException {
+
+ if (equalsJavaPrimitive(simpleType)) {
+ return ClassUtils.primitiveToWrapper(ClassUtils.getClass(simpleType)).getSimpleName();
+ } else {
+ return simpleType;
+ }
+
+ }
+
+ /**
+ * Returns the simple name of the type of a field in the pojoClass. If the type is a java primitive the name of the
+ * wrapper class is returned
+ *
+ * @param pojoClass {@link Class} the class object of the pojo
+ * @param fieldName {@link String} the name of the field
+ * @return String. The simple name of the field's type. The simple name of the wrapper class in case of java
+ * primitives
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public String boxJavaPrimitives(Class> pojoClass, String fieldName) throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+
+ if (equalsJavaPrimitive(pojoClass, fieldName)) {
+ return ClassUtils.primitiveToWrapper(pojoClass.getDeclaredField(fieldName).getType()).getSimpleName();
+ } else {
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ throw new IllegalAccessError("Could not find field " + fieldName + " in class " + pojoClass);
+ } else {
+ return field.getType().getSimpleName();
+ }
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive
+ *
+ * @param simpleType the type to be checked
+ * @return true iff simpleType is a Java primitive
+ */
+ public boolean equalsJavaPrimitive(String simpleType) {
+
+ try {
+ return ClassUtils.getClass(simpleType).isPrimitive();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive or wrapper
+ *
+ * @param simpleType the type to be checked
+ * @return true iff simpleType is a Java primitive or wrapper
+ */
+ public boolean equalsJavaPrimitiveOrWrapper(String simpleType) {
+
+ try {
+ return ClassUtils.isPrimitiveOrWrapper(ClassUtils.getClass(simpleType));
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the type of the field in the pojo's class is a java primitive
+ *
+ * @param pojoClass the {@link Class} object of the pojo
+ * @param fieldName the name of the field to be checked
+ * @return true iff the field is a java primitive
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean equalsJavaPrimitive(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ return false;
+ }
+
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ return false;
+ } else {
+ return field.getType().isPrimitive();
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive or a Java primitive array
+ *
+ * @param simpleType the Type name to be checked
+ * @return true iff {@link #equalsJavaPrimitive(String)} is true or if simpleType is an array with a primitive
+ * component
+ */
+ public boolean equalsJavaPrimitiveIncludingArrays(String simpleType) {
+
+ Class> klasse;
+
+ try {
+ klasse = ClassUtils.getClass(simpleType).getComponentType();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ return equalsJavaPrimitive(simpleType) || (klasse != null && klasse.isPrimitive());
+ }
+
+ /**
+ * Checks if the given field in the pojo class is a java primitive or an array of java primitives
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldName the name of the field to be checked
+ * @return true iff {@link #equalsJavaPrimitive(Class, String)} is true or the field is an array of primitives
+ * @throws NoSuchFieldException indicating something awfully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean equalsJavaPrimitiveIncludingArrays(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ return equalsJavaPrimitive(pojoClass, fieldName) || (pojoClass.getDeclaredField(fieldName).getType().isArray()
+ && pojoClass.getDeclaredField(fieldName).getType().getComponentType().isPrimitive());
+ }
+
+ /**
+ * Returns a cast statement for a given (java primitive, variable name) pair or nothing if the type isn't a java
+ * primitive
+ *
+ * @param simpleType Java Type
+ * @param varName Variable name
+ * @return String either of the form '((Java Primitive Object Type)varName)' if simpleType is a primitive or the empty
+ * String otherwise
+ * @throws ClassNotFoundException should not occur
+ */
+ public String castJavaPrimitives(String simpleType, String varName) throws ClassNotFoundException {
+
+ if (equalsJavaPrimitive(simpleType)) {
+ return String.format("((%1$s)%2$s)", boxJavaPrimitives(simpleType), varName);
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * Returns a cast statement for a given (java primitive, variable name) pair or nothing if the type isn't a java
+ * primitive
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldName the name of the field to be casted
+ * @return if fieldName points to a primitive field then a casted statement (e.g. for an int field:
+ * '((Integer)field)') or an empty String otherwise
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public String castJavaPrimitives(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ if (equalsJavaPrimitive(pojoClass, fieldName)) {
+ return String.format("((%1$s)%2$s)", boxJavaPrimitives(pojoClass, fieldName), fieldName);
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * @param pojoClass {@link Class} the class object of the pojo
+ * @param fieldName {@link String} the name of the field
+ * @return true if the field is an instance of java.utils.Collections
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean isCollection(Class> pojoClass, String fieldName) throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ return false;
+ }
+
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ return false;
+ } else {
+ return Collection.class.isAssignableFrom(field.getType());
+ }
+
+ }
+
+ /**
+ * Returns the Ext Type to a given java type
+ *
+ * @param simpleType any java type's simple name
+ * @return corresponding Ext type
+ */
+ public String getExtType(String simpleType) {
+
+ switch (simpleType) {
+ case "short":
+ case "Short":
+ case "int":
+ case "Integer":
+ case "long":
+ case "Long":
+ return "Integer";
+ case "float":
+ case "Float":
+ case "double":
+ case "Double":
+ return "Number";
+ case "boolean":
+ case "Boolean":
+ return "Boolean";
+ case "char":
+ case "Character":
+ case "String":
+ return "String";
+ case "Date":
+ return "Date";
+ default:
+ return "Field";
+ }
+ }
+
+ /**
+ * returns the Angular5 type associated with a Java primitive
+ *
+ * @param simpleType :{@link String} the type to be parsed
+ * @return the corresponding Angular type or 'any' otherwise
+ */
+ public String getAngularType(String simpleType) {
+
+ switch (simpleType) {
+ case "boolean":
+ return "boolean";
+ case "Boolean":
+ return "boolean";
+ case "short":
+ return "number";
+ case "Short":
+ return "number";
+ case "int":
+ return "number";
+ case "Integer":
+ return "number";
+ case "long":
+ return "number";
+ case "Long":
+ return "number";
+ case "float":
+ return "number";
+ case "Float":
+ return "number";
+ case "double":
+ return "number";
+ case "Double":
+ return "number";
+ case "char":
+ return "string";
+ case "Character":
+ return "string";
+ case "String":
+ return "string";
+ case "byte":
+ return "number";
+ default:
+ return "any";
+ }
+ }
+
+ /**
+ * returns the class name of the return type of a specific method.
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName {@link String} the name of the method
+ * @return the class name of the return type of the specified method
+ * @throws SecurityException If no method of the given name can be found
+ * @throws NoSuchMethodException If no method of the given name can be found
+ */
+ public String getReturnType(Class> pojoClass, String methodName) throws NoSuchMethodException, SecurityException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+ String s = "-";
+ Method method = findMethod(pojoClass, methodName);
+ if (method != null && !method.getReturnType().equals(Void.TYPE)) {
+ s = method.getReturnType().toString();
+ s = s.substring(s.lastIndexOf('.') + 1, s.length());
+ }
+ return s;
+ }
+
+ /**
+ *
+ * This methods returns the return type of the method in the given pojoClass which are annotated with the parameter
+ * annotatedClass
+ *
+ * @param pojoClass - The class in which to find if it has methods with annotatedClass
+ * @param annotatedClassName - The annotation which needs to be found
+ * @return Return type of the method annotated with the given annotation, else "null"
+ * @throws ClassNotFoundException if the annotated class name could not be found in the class path
+ */
+ @SuppressWarnings("unchecked")
+ public String getReturnTypeOfMethodAnnotatedWith(Class> pojoClass, String annotatedClassName)
+ throws ClassNotFoundException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+
+ Method[] methods = pojoClass.getDeclaredMethods();
+ for (Method method : methods) {
+ if (!method.getName().startsWith("get")) {
+ continue;
+ }
+ for (Annotation a : method.getAnnotations()) {
+ // better if (method.isAnnotationPresent(classObj)) {, but postponed as of different class
+ // loaders of a.getClass() and pojoClass.getClass()
+ if (a.getClass().getCanonicalName().equals(annotatedClassName)) {
+ return method.getReturnType().getSimpleName();
+ }
+ }
+ }
+ return "null";
+ }
+
+ /**
+ * returns the HTTP request type corresponding to an annotation type
+ *
+ * @param annotations The annotation to get the type name of
+ * @return the HTTP request type name of the selected annotation
+ */
+ public String getRequestType(Map annotations) {
+
+ if (annotations.containsKey("javax_ws_rs_GET")) {
+ return "GET";
+ } else if (annotations.containsKey("javax_ws_rs_PUT")) {
+ return "PUT";
+ } else if (annotations.containsKey("javax_ws_rs_POST")) {
+ return "POST";
+ } else if (annotations.containsKey("javax_ws_rs_DELETE")) {
+ return "DELETE";
+ } else if (annotations.containsKey("javax_ws_rs_PATCH")) {
+ return "PATCH";
+ } else {
+ return "-";
+ }
+ }
+
+ /**
+ * Helper method to find a class's specific method
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName The name of the method to be found
+ * @return The method object of the method to be found, null if it wasn't found
+ */
+ private Method findMethod(Class> pojoClass, String methodName) {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+ for (Method m : pojoClass.getMethods()) {
+ if (m.getName().equals(methodName)) {
+ return m;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Checks whether the class given by the full qualified name is an enum
+ *
+ * @param className full qualified class name
+ * @return true
if the class is an enum, false
otherwise
+ */
+ public boolean isEnum(String className) {
+
+ try {
+ return ClassUtils.getClass(className).isEnum();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), className);
+ return false;
+ }
+ }
+
+ /**
+ * Returns the first enum value of an enum class
+ *
+ * @param className full qualified class name
+ * @return the first enum value name found in order
+ */
+ public String getFirstEnumValue(String className) {
+
+ try {
+ Class> enumClass = ClassUtils.getClass(className);
+ Field[] declaredFields = enumClass.getDeclaredFields();
+ if (declaredFields.length > 0) {
+ return declaredFields[0].getName();
+ } else {
+ return null;
+ }
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), className);
+ return null;
+ }
+ }
+}
diff --git a/cobigen-templates/crud-openapi-java-server-app/pom.xml b/cobigen-templates/crud-openapi-java-server-app/pom.xml
index 66c044a54b..9d845790e1 100644
--- a/cobigen-templates/crud-openapi-java-server-app/pom.xml
+++ b/cobigen-templates/crud-openapi-java-server-app/pom.xml
@@ -10,4 +10,10 @@
${revision}
+
+
+ org.apache.commons
+ commons-lang3
+
+
\ No newline at end of file
diff --git a/cobigen-templates/crud-openapi-java-server-app/src/main/java/com/devonfw/cobigen/templates/devon4j/constants/Field.java b/cobigen-templates/crud-openapi-java-server-app/src/main/java/com/devonfw/cobigen/templates/devon4j/constants/Field.java
new file mode 100644
index 0000000000..5376daaea9
--- /dev/null
+++ b/cobigen-templates/crud-openapi-java-server-app/src/main/java/com/devonfw/cobigen/templates/devon4j/constants/Field.java
@@ -0,0 +1,48 @@
+package com.devonfw.cobigen.templates.devon4j.constants;
+
+/**
+ * Contains the used keys for the pojo field mapping
+ */
+public enum Field {
+
+ /**
+ * Name of the field
+ */
+ NAME("name"),
+ /**
+ * Type of the field
+ */
+ TYPE("type"),
+ /**
+ * Canonical Type of the field
+ */
+ CANONICAL_TYPE("canonicalType"),
+ /**
+ * The Javadoc of the field
+ */
+ JAVA_DOC("javaDoc"),
+ /**
+ * Annotations
+ */
+ ANNOTATIONS("annotations");
+
+ /**
+ * key value
+ */
+ private String value;
+
+ /**
+ * @param value of the key
+ */
+ Field(String value) {
+
+ this.value = value;
+ }
+
+ @Override
+ public String toString() {
+
+ return this.value;
+ }
+
+}
diff --git a/cobigen-templates/crud-openapi-java-server-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/DevonfwUtil.java b/cobigen-templates/crud-openapi-java-server-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/DevonfwUtil.java
new file mode 100644
index 0000000000..36e39b5e06
--- /dev/null
+++ b/cobigen-templates/crud-openapi-java-server-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/DevonfwUtil.java
@@ -0,0 +1,450 @@
+package com.devonfw.cobigen.templates.devon4j.utils;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.NodeList;
+
+import com.devonfw.cobigen.templates.devon4j.constants.Field;
+import com.sun.org.apache.xerces.internal.dom.DeferredElementNSImpl;
+
+/**
+ * A class for shared devon4j specific functions in the templates
+ *
+ */
+@SuppressWarnings("restriction")
+public class DevonfwUtil {
+
+ /**
+ * Check whether the given 'canonicalType' is a devon4j Entity, which is declared in the given 'component'
+ *
+ * @param canonicalType the type name
+ * @param component the component name
+ * @return true iff the canonicalType is a devon Entity
+ */
+ public boolean isEntityInComponent(String canonicalType, String component) {
+
+ return canonicalType.matches(String.format(".+%1$s\\.dataaccess\\.api\\.[A-Za-z0-9]+Entity(<.*)?", component));
+ }
+
+ /**
+ * Check whether the given 'canonicalType' is declared in the given 'component'
+ *
+ * @param canonicalType the type name
+ * @param component the component name
+ * @return true iff the canonicalType is inside the given component
+ */
+ public boolean isTypeInComponent(String canonicalType, String component) {
+
+ return canonicalType.matches(String.format("%1$s.[A-Za-z0-9]+(<.*)?", component));
+ }
+
+ /**
+ * Determines the ID getter for a given 'field' dependent on whether the getter should access the ID via an object
+ * reference or a direct ID getter
+ *
+ * @param field the field
+ * @param byObjectReference boolean
+ * @param component the devon4j component name
+ * @return 'get' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)} + '()' with
+ * capitalize=true
+ */
+ public String resolveIdGetter(Map field, boolean byObjectReference, String component) {
+
+ // If field comes from an UML file
+ if (field.getClass().toGenericString().contains("freemarker.ext.beans.HashAdapter")) {
+ DeferredElementNSImpl umlNode = (DeferredElementNSImpl) field;
+ return resolveIdGetter(umlNode, byObjectReference, component);
+ }
+ return "get" + resolveIdVariableNameOrSetterGetterSuffix(field, byObjectReference, true, component) + "()";
+ }
+
+ /**
+ * Determines the ID getter for a given 'field' dependent on whether the getter should access the ID via an object
+ * reference or a direct ID getter
+ *
+ * This method is used when the field parameter comes from an UML file. The name and type of the attributes must be
+ * pre-processed for later inserting them inside the HashMap.
+ *
+ * @param field the field
+ * @param byObjectReference boolean
+ * @param component the devon4j component name
+ * @return 'get' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)} + '()' with
+ * capitalize=true
+ */
+ public String resolveIdGetter(DeferredElementNSImpl field, boolean byObjectReference, String component) {
+
+ HashMap nodeHash = new HashMap<>();
+
+ // Putting the name of the attribute to the hash
+ nodeHash.put(Field.NAME.toString(), field.getAttribute("name"));
+
+ // Putting the type of the attribute to the hash
+ NodeList childs = field.getChildNodes();
+ for (int i = 0; i < childs.getLength(); i++) {
+ // Retrieve "type" tag
+ if (childs.item(i).getNodeName().equals("type")) {
+ NamedNodeMap attrs = childs.item(i).getAttributes();
+ for (int j = 0; j < attrs.getLength(); j++) {
+ Attr attribute = (Attr) attrs.item(j);
+ // Try to find the attribute that contains the type
+ if (attribute.getName().equals("xmi:idref")) {
+ nodeHash.put(Field.TYPE.toString(), attribute.getName().replace("EAJava_", ""));
+ }
+ }
+ }
+ }
+ return "get" + resolveIdVariableNameOrSetterGetterSuffix(nodeHash, byObjectReference, true, component) + "()";
+
+ }
+
+ /**
+ * Determines the ID getter for a given 'field' dependent on whether the getter should access the ID via an object
+ * reference or a direct ID getter
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldMap the field mapping
+ * @param byObjectReference boolean
+ * @param component the devon4j component name
+ * @return 'get' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)} + '()' with
+ * capitalize=true
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdGetter(Class> pojoClass, Map fieldMap, boolean byObjectReference,
+ String component) throws NoSuchFieldException, SecurityException {
+
+ return "get" + resolveIdVariableNameOrSetterGetterSuffix(pojoClass, fieldMap, byObjectReference, true, component)
+ + "()";
+ }
+
+ /**
+ * same as {@link #resolveIdGetter(Map, boolean, String)} but with byObjectReference=false and component=""
+ *
+ * @param field the field
+ * @return 'get' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map,boolean,boolean,String)} + '()' with
+ * capitalize=true
+ */
+ public String resolveIdGetter(Map field) {
+
+ return this.resolveIdGetter(field, false, "");
+ }
+
+ /**
+ * same as {@link #resolveIdGetter(Class,Map,boolean,String)} but with byObjectReference=false and component=""
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldMap the field mapping
+ * @return 'get' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map,boolean,boolean,String)} + '()' with
+ * capitalize=true
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdGetter(Class> pojoClass, Map fieldMap)
+ throws NoSuchFieldException, SecurityException {
+
+ return resolveIdGetter(pojoClass, fieldMap, false, "");
+ }
+
+ /**
+ * Determines the ID setter for a given 'field' dependent on whether the setter should access the ID via an object
+ * reference or a direct ID setter. In contrast to resolveIdGetter, this function does not generate the function
+ * parenthesis to enable parameter declaration.
+ *
+ * @param field the field
+ * @param byObjectReference boolean
+ * @param component the devon4j component name
+ * @return 'set' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)} with
+ * capitalize=true
+ */
+ public String resolveIdSetter(Map field, boolean byObjectReference, String component) {
+
+ return "set" + resolveIdVariableNameOrSetterGetterSuffix(field, byObjectReference, true, component);
+ }
+
+ /**
+ * same as {@link #resolveIdSetter(Map, boolean, String)} but with byObjectReference=false and component=""
+ *
+ * @param field the field
+ * @return 'set' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)} with
+ * capitalize=true
+ */
+ public String resolveIdSetter(Map field) {
+
+ return this.resolveIdSetter(field, false, "");
+ }
+
+ /**
+ * Determines the ID setter for a given 'field' dependent on whether the setter should access the ID via an object
+ * reference or a direct ID setter. In contrast to resolveIdGetter, this function does not generate the function
+ * parenthesis to enable parameter declaration.
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldMap the field mapping
+ * @param byObjectReference boolean
+ * @param component the devon4j component name
+ * @return 'set'+ {@link #resolveIdVariableNameOrSetterGetterSuffix(Map,boolean,boolean,String)} with capitalize=true
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdSetter(Class> pojoClass, Map fieldMap, boolean byObjectReference,
+ String component) throws NoSuchFieldException, SecurityException {
+
+ return "set" + resolveIdVariableNameOrSetterGetterSuffix(pojoClass, fieldMap, byObjectReference, true, component);
+ }
+
+ /**
+ * same as {@link #resolveIdSetter(Class,Map,boolean,String)} but with byObjectReference=false and component=""
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldMap the field mapping
+ * @return 'set' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map,boolean,boolean,String)} with capitalize=true
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdSetter(Class> pojoClass, Map fieldMap)
+ throws NoSuchFieldException, SecurityException {
+
+ return resolveIdSetter(pojoClass, fieldMap, false, "");
+ }
+
+ /**
+ * Determines the variable name for the id value of the 'field'
+ *
+ * @param field the field
+ * @return {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)}) with
+ * byObjectReference=false, capitalize=false and component=""
+ */
+ public String resolveIdVariableName(Map field) {
+
+ // the component is passed down as an empty string since byObjectReference is false and therefore the
+ // component is
+ // never touched
+ return resolveIdVariableNameOrSetterGetterSuffix(field, false, false, "");
+ }
+
+ /**
+ * Determines the variable name for the id value of the specified field in the pojo
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldMap the field mapping
+ * @return {@link #resolveIdVariableNameOrSetterGetterSuffix(Class, Map, boolean, boolean, String)}) with
+ * byObjectReference=false, capitalize=false and component=""
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdVariableName(Class> pojoClass, Map fieldMap)
+ throws NoSuchFieldException, SecurityException {
+
+ // the component is passed down as an empty string since byObjectReference is false and therefore the
+ // component is
+ // never touched
+ return resolveIdVariableNameOrSetterGetterSuffix(pojoClass, fieldMap, false, false, "");
+ }
+
+ /**
+ * Determines the ID setter/getter suffix for a given 'field' dependent on whether the setter/getter should access the
+ * ID via an object reference or a direct ID setter/getter
+ *
+ * @param field the field
+ * @param byObjectReference boolean
+ * @param capitalize if the field name should be capitalized
+ * @param component the devon4j component. Only needed if $byObjectReference is true
+ * @return idVariable name or getter/setter suffix
+ */
+ public String resolveIdVariableNameOrSetterGetterSuffix(Map field, boolean byObjectReference,
+ boolean capitalize, String component) {
+
+ String fieldName = (String) field.get(Field.NAME.toString());
+ if (capitalize) {
+ fieldName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
+ }
+ String suffix = "";
+
+ String fieldType = (String) field.get(Field.TYPE.toString());
+ String fieldCType = (String) field.get(Field.CANONICAL_TYPE.toString());
+ if (fieldType.contains("Entity")) {
+ if (fieldCType.startsWith("java.util.List") || fieldCType.startsWith("java.util.Set")) {
+ suffix = "Ids";
+ if (fieldName.endsWith("s")) {
+ // Assume trailing 's' as indicator for a plural
+ fieldName = fieldName.substring(0, fieldName.length() - 1);
+ }
+ } else {
+ suffix = "Id";
+ }
+ if (byObjectReference && isTypeInComponent(fieldCType, component)) {
+ // direct references for Entities in same component, so get id of the object reference
+ suffix = "().getId";
+ }
+ }
+
+ return fieldName + suffix;
+
+ }
+
+ /**
+ * Determines the ID setter/getter suffix for a given 'field' dependent on whether the setter/getter should access the
+ * ID via an object reference or a direct ID setter/getter
+ *
+ * @param pojoClass the {@link Class} object of the pojo
+ * @param fieldMap the field mapping
+ * @param byObjectReference boolean
+ * @param capitalize if the field name should be capitalized
+ * @param component the devon4j component. Only needed if byObjectReference is true
+ * @return idVariable name or getter/setter suffix
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdVariableNameOrSetterGetterSuffix(Class> pojoClass, Map fieldMap,
+ boolean byObjectReference, boolean capitalize, String component) throws NoSuchFieldException, SecurityException {
+
+ String resultName = (String) fieldMap.get(Field.NAME.toString());
+ if (capitalize) {
+ resultName = resultName.substring(0, 1).toUpperCase() + resultName.substring(1);
+ }
+ String suffix = "";
+ String fieldType = (String) fieldMap.get(Field.TYPE.toString());
+ String fieldName = (String) fieldMap.get(Field.NAME.toString());
+ if (fieldType.contains("Entity")) {
+ if (Collection.class.isAssignableFrom(pojoClass.getDeclaredField(fieldName).getType())) {
+ suffix = "Ids";
+ if (resultName.endsWith("s")) {
+ // Assume trailing 's' as indicator for a plural
+ resultName = resultName.substring(0, resultName.length() - 1);
+ }
+ } else {
+ suffix = "Id";
+ }
+ if (byObjectReference
+ && isEntityInComponent(pojoClass.getDeclaredField(fieldName).getType().getName(), component)) {
+ // direct references for Entities in same component, so get id of the object reference
+ suffix = "().getId";
+ }
+ }
+
+ return resultName + suffix;
+
+ }
+
+ /**
+ * Returns the argument type of the list or set from a field. If the string contains "Entity" it will remove that
+ * part. For example, if we have a List <SampleEntity> it will return "Sample"
+ *
+ * @param field the field
+ * @param pojoClass the object class of the Entity that contains the field
+ * @return fieldType argument of the list
+ * @throws SecurityException if field type could not accessed
+ * @throws NoSuchFieldException if field could not be found
+ */
+ public String getListArgumentType(Map field, Class> pojoClass)
+ throws NoSuchFieldException, SecurityException {
+
+ JavaUtil javaUtil = new JavaUtil();
+
+ String fieldType = (String) field.get(Field.TYPE.toString());
+ String fieldName = (String) field.get(Field.NAME.toString());
+
+ if (fieldType.contains("Entity")) {
+ if (javaUtil.isCollection(pojoClass, fieldName)) {
+
+ fieldType = fieldType.replace("Entity", "");
+ // Regex: Extracts the argument type of the list 'List' => type
+ String regex = "(?<=\\<).+?(?=\\>)";
+ Pattern pattern = Pattern.compile(regex);
+ Matcher regexMatcher = pattern.matcher(fieldType);
+
+ if (regexMatcher.find()) {
+ fieldType = regexMatcher.group(0);
+ }
+ }
+ }
+ return fieldType;
+
+ }
+
+ /**
+ * Converts all occurrences of devon4j Entity types in the given 'field' simple type (possibly generic) to Longs
+ *
+ * @param field the field
+ * @return the field type as String. If field type contains 'Entity' the result is Long
+ */
+ public String getSimpleEntityTypeAsLongReference(Map field) {
+
+ String fieldType = (String) field.get(Field.TYPE.toString());
+ if (fieldType.endsWith("Entity")) {
+ fieldType = fieldType.replaceAll("[^<>]+Entity", "Long");
+ }
+ return fieldType;
+ }
+
+ /**
+ * If the string last character is an 's', then it gets removed
+ *
+ * @param targetClassName string to remove plural
+ * @return string without 's'
+ */
+ public String removePlural(String targetClassName) {
+
+ if (targetClassName.charAt(targetClassName.length() - 1) == 's') {
+ targetClassName = targetClassName.substring(0, targetClassName.length() - 1);
+ }
+ return targetClassName;
+ }
+
+ /**
+ * Checks whether the operation with the given ID corresponds to any standard CRUD method name.
+ *
+ * @param operationId operation ID interpreted as method name
+ * @param entityName entity name to check standard CRUD methods for
+ * @return true
if the operation ID maps any standard CRUD method name, false
otherwise
+ */
+ public boolean isCrudOperation(String operationId, String entityName) {
+
+ if (operationId == null) {
+ return false;
+ }
+ String opIdLowerCase = operationId.toLowerCase();
+ String entityNameLowerCase = entityName.toLowerCase();
+ if (opIdLowerCase.contains(entityNameLowerCase)) {
+ return opIdLowerCase.equals("find" + entityNameLowerCase)
+ || opIdLowerCase.equals("find" + entityNameLowerCase + "Etos")
+ || opIdLowerCase.equals("delete" + entityNameLowerCase) || opIdLowerCase.equals("save" + entityNameLowerCase);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Converts the given media type to the spring Java enum value
+ *
+ * @param mediaType to be converted
+ * @return the spring enum value representing the given media type
+ */
+ public String getSpringMediaType(String mediaType) {
+
+ switch (mediaType) {
+ case "application/xml":
+ return "APPLICATION_XML_VALUE";
+ case "application / x-www-form-urlencoded":
+ return "APPLICATION_FORM_URLENCODED_VALUE";
+ case "multipart/form-data":
+ return "MULTIPART_FORM_DATA_VALUE";
+ case "text/plain":
+ return "TEXT_PLAIN_VALUE";
+ case "text/html":
+ return "TEXT_HTML_VALUE";
+ case "application/pdf":
+ return "APPLICATION_PDF_VALUE";
+ case "image/png":
+ return "IMAGE_PNG_VALUE";
+ default:
+ return "APPLICATION_JSON_VALUE";
+ }
+ }
+}
\ No newline at end of file
diff --git a/cobigen-templates/crud-openapi-java-server-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java b/cobigen-templates/crud-openapi-java-server-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java
new file mode 100644
index 0000000000..ced2f5fde2
--- /dev/null
+++ b/cobigen-templates/crud-openapi-java-server-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java
@@ -0,0 +1,464 @@
+package com.devonfw.cobigen.templates.devon4j.utils;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.commons.lang3.ClassUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Provides type operations, mainly checks and casts for Java Primitives, to be used in the templates
+ *
+ */
+public class JavaUtil {
+
+ /**
+ * Logger for this class
+ */
+ private static final Logger LOG = LoggerFactory.getLogger(JavaUtil.class);
+
+ /**
+ * The constructor.
+ */
+ public JavaUtil() {
+
+ // Empty for CobiGen to automatically instantiate it
+ }
+
+ /**
+ * Returns the Object version of a Java primitive or the input if the input isn't a java primitive
+ *
+ * @param simpleType String
+ * @return the corresponding object wrapper type simple name of the input if the input is the name of a primitive java
+ * type. The input itself if not. (e.g. "int" results in "Integer")
+ * @throws ClassNotFoundException should not occur.
+ */
+ public String boxJavaPrimitives(String simpleType) throws ClassNotFoundException {
+
+ if (equalsJavaPrimitive(simpleType)) {
+ return ClassUtils.primitiveToWrapper(ClassUtils.getClass(simpleType)).getSimpleName();
+ } else {
+ return simpleType;
+ }
+
+ }
+
+ /**
+ * Returns the simple name of the type of a field in the pojoClass. If the type is a java primitive the name of the
+ * wrapper class is returned
+ *
+ * @param pojoClass {@link Class} the class object of the pojo
+ * @param fieldName {@link String} the name of the field
+ * @return String. The simple name of the field's type. The simple name of the wrapper class in case of java
+ * primitives
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public String boxJavaPrimitives(Class> pojoClass, String fieldName) throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+
+ if (equalsJavaPrimitive(pojoClass, fieldName)) {
+ return ClassUtils.primitiveToWrapper(pojoClass.getDeclaredField(fieldName).getType()).getSimpleName();
+ } else {
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ throw new IllegalAccessError("Could not find field " + fieldName + " in class " + pojoClass);
+ } else {
+ return field.getType().getSimpleName();
+ }
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive
+ *
+ * @param simpleType the type to be checked
+ * @return true iff simpleType is a Java primitive
+ */
+ public boolean equalsJavaPrimitive(String simpleType) {
+
+ try {
+ return ClassUtils.getClass(simpleType).isPrimitive();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive or wrapper
+ *
+ * @param simpleType the type to be checked
+ * @return true iff simpleType is a Java primitive or wrapper
+ */
+ public boolean equalsJavaPrimitiveOrWrapper(String simpleType) {
+
+ try {
+ return ClassUtils.isPrimitiveOrWrapper(ClassUtils.getClass(simpleType));
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the type of the field in the pojo's class is a java primitive
+ *
+ * @param pojoClass the {@link Class} object of the pojo
+ * @param fieldName the name of the field to be checked
+ * @return true iff the field is a java primitive
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean equalsJavaPrimitive(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ return false;
+ }
+
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ return false;
+ } else {
+ return field.getType().isPrimitive();
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive or a Java primitive array
+ *
+ * @param simpleType the Type name to be checked
+ * @return true iff {@link #equalsJavaPrimitive(String)} is true or if simpleType is an array with a primitive
+ * component
+ */
+ public boolean equalsJavaPrimitiveIncludingArrays(String simpleType) {
+
+ Class> klasse;
+
+ try {
+ klasse = ClassUtils.getClass(simpleType).getComponentType();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ return equalsJavaPrimitive(simpleType) || (klasse != null && klasse.isPrimitive());
+ }
+
+ /**
+ * Checks if the given field in the pojo class is a java primitive or an array of java primitives
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldName the name of the field to be checked
+ * @return true iff {@link #equalsJavaPrimitive(Class, String)} is true or the field is an array of primitives
+ * @throws NoSuchFieldException indicating something awfully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean equalsJavaPrimitiveIncludingArrays(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ return equalsJavaPrimitive(pojoClass, fieldName) || (pojoClass.getDeclaredField(fieldName).getType().isArray()
+ && pojoClass.getDeclaredField(fieldName).getType().getComponentType().isPrimitive());
+ }
+
+ /**
+ * Returns a cast statement for a given (java primitive, variable name) pair or nothing if the type isn't a java
+ * primitive
+ *
+ * @param simpleType Java Type
+ * @param varName Variable name
+ * @return String either of the form '((Java Primitive Object Type)varName)' if simpleType is a primitive or the empty
+ * String otherwise
+ * @throws ClassNotFoundException should not occur
+ */
+ public String castJavaPrimitives(String simpleType, String varName) throws ClassNotFoundException {
+
+ if (equalsJavaPrimitive(simpleType)) {
+ return String.format("((%1$s)%2$s)", boxJavaPrimitives(simpleType), varName);
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * Returns a cast statement for a given (java primitive, variable name) pair or nothing if the type isn't a java
+ * primitive
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldName the name of the field to be casted
+ * @return if fieldName points to a primitive field then a casted statement (e.g. for an int field:
+ * '((Integer)field)') or an empty String otherwise
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public String castJavaPrimitives(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ if (equalsJavaPrimitive(pojoClass, fieldName)) {
+ return String.format("((%1$s)%2$s)", boxJavaPrimitives(pojoClass, fieldName), fieldName);
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * @param pojoClass {@link Class} the class object of the pojo
+ * @param fieldName {@link String} the name of the field
+ * @return true if the field is an instance of java.utils.Collections
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean isCollection(Class> pojoClass, String fieldName) throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ return false;
+ }
+
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ return false;
+ } else {
+ return Collection.class.isAssignableFrom(field.getType());
+ }
+
+ }
+
+ /**
+ * Returns the Ext Type to a given java type
+ *
+ * @param simpleType any java type's simple name
+ * @return corresponding Ext type
+ */
+ public String getExtType(String simpleType) {
+
+ switch (simpleType) {
+ case "short":
+ case "Short":
+ case "int":
+ case "Integer":
+ case "long":
+ case "Long":
+ return "Integer";
+ case "float":
+ case "Float":
+ case "double":
+ case "Double":
+ return "Number";
+ case "boolean":
+ case "Boolean":
+ return "Boolean";
+ case "char":
+ case "Character":
+ case "String":
+ return "String";
+ case "Date":
+ return "Date";
+ default:
+ return "Field";
+ }
+ }
+
+ /**
+ * returns the Angular5 type associated with a Java primitive
+ *
+ * @param simpleType :{@link String} the type to be parsed
+ * @return the corresponding Angular type or 'any' otherwise
+ */
+ public String getAngularType(String simpleType) {
+
+ switch (simpleType) {
+ case "boolean":
+ return "boolean";
+ case "Boolean":
+ return "boolean";
+ case "short":
+ return "number";
+ case "Short":
+ return "number";
+ case "int":
+ return "number";
+ case "Integer":
+ return "number";
+ case "long":
+ return "number";
+ case "Long":
+ return "number";
+ case "float":
+ return "number";
+ case "Float":
+ return "number";
+ case "double":
+ return "number";
+ case "Double":
+ return "number";
+ case "char":
+ return "string";
+ case "Character":
+ return "string";
+ case "String":
+ return "string";
+ case "byte":
+ return "number";
+ default:
+ return "any";
+ }
+ }
+
+ /**
+ * returns the class name of the return type of a specific method.
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName {@link String} the name of the method
+ * @return the class name of the return type of the specified method
+ * @throws SecurityException If no method of the given name can be found
+ * @throws NoSuchMethodException If no method of the given name can be found
+ */
+ public String getReturnType(Class> pojoClass, String methodName) throws NoSuchMethodException, SecurityException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+ String s = "-";
+ Method method = findMethod(pojoClass, methodName);
+ if (method != null && !method.getReturnType().equals(Void.TYPE)) {
+ s = method.getReturnType().toString();
+ s = s.substring(s.lastIndexOf('.') + 1, s.length());
+ }
+ return s;
+ }
+
+ /**
+ *
+ * This methods returns the return type of the method in the given pojoClass which are annotated with the parameter
+ * annotatedClass
+ *
+ * @param pojoClass - The class in which to find if it has methods with annotatedClass
+ * @param annotatedClassName - The annotation which needs to be found
+ * @return Return type of the method annotated with the given annotation, else "null"
+ * @throws ClassNotFoundException if the annotated class name could not be found in the class path
+ */
+ @SuppressWarnings("unchecked")
+ public String getReturnTypeOfMethodAnnotatedWith(Class> pojoClass, String annotatedClassName)
+ throws ClassNotFoundException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+
+ Method[] methods = pojoClass.getDeclaredMethods();
+ for (Method method : methods) {
+ if (!method.getName().startsWith("get")) {
+ continue;
+ }
+ for (Annotation a : method.getAnnotations()) {
+ // better if (method.isAnnotationPresent(classObj)) {, but postponed as of different class
+ // loaders of a.getClass() and pojoClass.getClass()
+ if (a.getClass().getCanonicalName().equals(annotatedClassName)) {
+ return method.getReturnType().getSimpleName();
+ }
+ }
+ }
+ return "null";
+ }
+
+ /**
+ * returns the HTTP request type corresponding to an annotation type
+ *
+ * @param annotations The annotation to get the type name of
+ * @return the HTTP request type name of the selected annotation
+ */
+ public String getRequestType(Map annotations) {
+
+ if (annotations.containsKey("javax_ws_rs_GET")) {
+ return "GET";
+ } else if (annotations.containsKey("javax_ws_rs_PUT")) {
+ return "PUT";
+ } else if (annotations.containsKey("javax_ws_rs_POST")) {
+ return "POST";
+ } else if (annotations.containsKey("javax_ws_rs_DELETE")) {
+ return "DELETE";
+ } else if (annotations.containsKey("javax_ws_rs_PATCH")) {
+ return "PATCH";
+ } else {
+ return "-";
+ }
+ }
+
+ /**
+ * Helper method to find a class's specific method
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName The name of the method to be found
+ * @return The method object of the method to be found, null if it wasn't found
+ */
+ private Method findMethod(Class> pojoClass, String methodName) {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+ for (Method m : pojoClass.getMethods()) {
+ if (m.getName().equals(methodName)) {
+ return m;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Checks whether the class given by the full qualified name is an enum
+ *
+ * @param className full qualified class name
+ * @return true
if the class is an enum, false
otherwise
+ */
+ public boolean isEnum(String className) {
+
+ try {
+ return ClassUtils.getClass(className).isEnum();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), className);
+ return false;
+ }
+ }
+
+ /**
+ * Returns the first enum value of an enum class
+ *
+ * @param className full qualified class name
+ * @return the first enum value name found in order
+ */
+ public String getFirstEnumValue(String className) {
+
+ try {
+ Class> enumClass = ClassUtils.getClass(className);
+ Field[] declaredFields = enumClass.getDeclaredFields();
+ if (declaredFields.length > 0) {
+ return declaredFields[0].getName();
+ } else {
+ return null;
+ }
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), className);
+ return null;
+ }
+ }
+}
diff --git a/cobigen-templates/crud-openapi-java-server-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/OpenApiUtil.java b/cobigen-templates/crud-openapi-java-server-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/OpenApiUtil.java
new file mode 100644
index 0000000000..a93288f45a
--- /dev/null
+++ b/cobigen-templates/crud-openapi-java-server-app/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/OpenApiUtil.java
@@ -0,0 +1,255 @@
+package com.devonfw.cobigen.templates.devon4j.utils;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+
+/** Utils on OpenAPI template model */
+public class OpenApiUtil {
+
+ /**
+ * Prints javax validation constraints from an OpenAPI model
+ *
+ * @param constraints OpenAPI model constraints
+ * @return the list of supported annotations in Java syntax
+ */
+ public String printJavaConstraints(Map constraints) {
+
+ String consts = "";
+ if (constraints.get("maximum") != null) {
+ consts = consts + "@Max(" + constraints.get("maximum") + ")";
+ }
+ if (constraints.get("minimum") != null) {
+ consts = consts + "@Min(" + constraints.get("minimum") + ")";
+ }
+ if (constraints.get("maxLength") != null) {
+ consts = consts + "@Size(max=" + constraints.get("maxLength");
+ if (constraints.get("minLength") != null) {
+ consts = consts + ", min=" + constraints.get("minLength");
+ }
+ consts = consts + ")";
+ } else {
+ if (constraints.get("minLength") != null) {
+ consts = consts + "@Size(min=" + constraints.get("minLength");
+ if (constraints.get("maxLength") != null) {
+ consts = consts + ", max=" + constraints.get("maxLength");
+ }
+ consts = consts + ")";
+ }
+ }
+ return consts;
+ }
+
+ /**
+ * Prints the return type of a response based on the OpenAPI model
+ *
+ * @param response the OpenAPI model of a response
+ * @return simple type of the response return type in Java syntax
+ */
+ public String printJavaServiceResponseReturnType(Map response) {
+
+ String returnType = toJavaType(response, false);
+ if ((boolean) response.get("isVoid")) {
+ return "void";
+ }
+ if ((boolean) response.get("isArray")) {
+ if ((boolean) response.get("isEntity")) {
+ if (returnType.contains("Entity")) {
+ return "List<" + returnType + ">";
+ } else {
+ return "List<" + returnType + "Entity>";
+ }
+ } else {
+ return "List<" + returnType + ">";
+ }
+ } else if ((boolean) response.get("isPaginated")) {
+ if ((boolean) response.get("isEntity")) {
+ if (returnType.contains("Entity")) {
+ return "Page<" + returnType + ">";
+ } else {
+ return "Page<" + returnType + "Entity>";
+ }
+ } else {
+ return "Page<" + returnType + ">";
+ }
+ } else {
+ return returnType;
+ }
+ }
+
+ /**
+ * Returns the Java type corresponding to the OpenAPI type definition. If the type could not be matched, Object will
+ * be returned.
+ *
+ * @param parameter OpenAPI model of a parameter
+ * @param simpleType if a Java simple type should be returned if possible
+ * @return the Java type
+ */
+ public String toJavaType(Map parameter, boolean simpleType) {
+
+ String typeConverted = null;
+ String format = (String) parameter.get("format");
+ String type = (String) parameter.get("type");
+ boolean isCollection = false;
+ if (parameter.get("isCollection") != null) {
+ isCollection = (boolean) parameter.get("isCollection");
+ }
+
+ boolean isEntity = (boolean) parameter.get("isEntity");
+
+ if (type != null) {
+ switch (type.toLowerCase()) {
+ case "integer":
+ if (format != null) {
+ switch (format) {
+ case "int32":
+ typeConverted = simpleType ? "int" : "Integer";
+ break;
+ case "int64":
+ typeConverted = simpleType ? "long" : "Long";
+ break;
+ default:
+ typeConverted = BigInteger.class.getSimpleName();
+ break;
+ }
+ } else {
+ typeConverted = BigInteger.class.getSimpleName();
+ }
+ break;
+ case "number":
+ if (format != null) {
+ switch (format) {
+ case "float":
+ typeConverted = simpleType ? "float" : "Float";
+ break;
+ case "double":
+ typeConverted = simpleType ? "double" : "Double";
+ break;
+ default:
+ typeConverted = BigDecimal.class.getSimpleName();
+ break;
+ }
+ } else {
+ typeConverted = BigDecimal.class.getSimpleName();
+ }
+ break;
+ case "string":
+ if (format != null) {
+ switch (format) {
+ case "date":
+ typeConverted = LocalDate.class.getSimpleName();
+ break;
+ case "date-time":
+ typeConverted = Instant.class.getSimpleName();
+ break;
+ case "binary":
+ typeConverted = simpleType ? "float" : "Float";
+ break;
+ case "email":
+ case "password":
+ typeConverted = String.class.getSimpleName();
+ break;
+ default:
+ typeConverted = "String";
+ break;
+ }
+ } else {
+ typeConverted = "String";
+ }
+ break;
+ case "boolean":
+ typeConverted = simpleType ? "boolean" : "Boolean";
+ break;
+ default:
+ typeConverted = "void";
+ break;
+ }
+ } else {
+ typeConverted = "void";
+ }
+
+ if (isCollection) {
+ if (isEntity) {
+ return "List<" + parameter.get("type") + ">";
+ } else {
+ return "List<" + typeConverted + ">";
+ }
+ } else if (isEntity) {
+ return (String) parameter.get("type");
+ }
+ return typeConverted;
+ }
+
+ /**
+ * Returns the TypeScript type corresponding to the OpenAPI type definition. If the type could not be matched, the
+ * same value will be returned.
+ *
+ * @param parameter OpenAPI model of a parameter
+ * @return the Java type
+ */
+ // getOaspTypeFromOpenAPI
+ public String toTypeScriptType(Map parameter) {
+
+ String typeConverted = null;
+ String type = (String) parameter.get("type");
+ boolean isCollection = false;
+ if (parameter.get("isCollection") != null) {
+ isCollection = (boolean) parameter.get("isCollection");
+ }
+
+ boolean isEntity = (boolean) parameter.get("isEntity");
+
+ if (type != null) {
+ switch (type.toLowerCase()) {
+ case "integer":
+ typeConverted = "number";
+ break;
+ default:
+ typeConverted = type;
+ break;
+ }
+ } else {
+ typeConverted = "undefined";
+ }
+
+ if (isCollection) {
+ if (isEntity) {
+ return parameter.get("type") + "[]";
+ } else {
+ return typeConverted + "[]";
+ }
+ } else if (isEntity) {
+ return (String) parameter.get("type");
+ }
+ return typeConverted;
+ }
+
+ /**
+ * Prints the service operation name based on the operationId or generates one based on the servicePath while printing
+ * a comment how to get better service names.
+ *
+ * @param operation operation Model of the OpenAPI model
+ * @param servicePath service path of the
+ * @return the service method name
+ */
+ public String printServiceOperationName(Map operation, String servicePath) {
+
+ String operationId = (String) operation.get("operationId");
+ if (StringUtils.isEmpty(operationId)) {
+ String[] split = servicePath.split("/");
+ String lastSegment;
+ if (!split[split.length - 1].isEmpty()) {
+ lastSegment = split[split.length - 1];
+ } else {
+ lastSegment = split[split.length - 2];
+ }
+ return ((String) operation.get("type")) + lastSegment;
+ } else {
+ return operationId;
+ }
+ }
+}
diff --git a/cobigen-templates/crud-openapi-net/pom.xml b/cobigen-templates/crud-openapi-net/pom.xml
index 72c9d20582..ddd28d9c64 100644
--- a/cobigen-templates/crud-openapi-net/pom.xml
+++ b/cobigen-templates/crud-openapi-net/pom.xml
@@ -10,4 +10,10 @@
${revision}
+
+
+ org.apache.commons
+ commons-lang3
+
+
\ No newline at end of file
diff --git a/cobigen-templates/crud-openapi-net/src/main/java/com/devonfw/cobigen/templates/devon4j/constants/Field.java b/cobigen-templates/crud-openapi-net/src/main/java/com/devonfw/cobigen/templates/devon4j/constants/Field.java
new file mode 100644
index 0000000000..5376daaea9
--- /dev/null
+++ b/cobigen-templates/crud-openapi-net/src/main/java/com/devonfw/cobigen/templates/devon4j/constants/Field.java
@@ -0,0 +1,48 @@
+package com.devonfw.cobigen.templates.devon4j.constants;
+
+/**
+ * Contains the used keys for the pojo field mapping
+ */
+public enum Field {
+
+ /**
+ * Name of the field
+ */
+ NAME("name"),
+ /**
+ * Type of the field
+ */
+ TYPE("type"),
+ /**
+ * Canonical Type of the field
+ */
+ CANONICAL_TYPE("canonicalType"),
+ /**
+ * The Javadoc of the field
+ */
+ JAVA_DOC("javaDoc"),
+ /**
+ * Annotations
+ */
+ ANNOTATIONS("annotations");
+
+ /**
+ * key value
+ */
+ private String value;
+
+ /**
+ * @param value of the key
+ */
+ Field(String value) {
+
+ this.value = value;
+ }
+
+ @Override
+ public String toString() {
+
+ return this.value;
+ }
+
+}
diff --git a/cobigen-templates/crud-openapi-net/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/DevonfwUtil.java b/cobigen-templates/crud-openapi-net/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/DevonfwUtil.java
new file mode 100644
index 0000000000..36e39b5e06
--- /dev/null
+++ b/cobigen-templates/crud-openapi-net/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/DevonfwUtil.java
@@ -0,0 +1,450 @@
+package com.devonfw.cobigen.templates.devon4j.utils;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.NodeList;
+
+import com.devonfw.cobigen.templates.devon4j.constants.Field;
+import com.sun.org.apache.xerces.internal.dom.DeferredElementNSImpl;
+
+/**
+ * A class for shared devon4j specific functions in the templates
+ *
+ */
+@SuppressWarnings("restriction")
+public class DevonfwUtil {
+
+ /**
+ * Check whether the given 'canonicalType' is a devon4j Entity, which is declared in the given 'component'
+ *
+ * @param canonicalType the type name
+ * @param component the component name
+ * @return true iff the canonicalType is a devon Entity
+ */
+ public boolean isEntityInComponent(String canonicalType, String component) {
+
+ return canonicalType.matches(String.format(".+%1$s\\.dataaccess\\.api\\.[A-Za-z0-9]+Entity(<.*)?", component));
+ }
+
+ /**
+ * Check whether the given 'canonicalType' is declared in the given 'component'
+ *
+ * @param canonicalType the type name
+ * @param component the component name
+ * @return true iff the canonicalType is inside the given component
+ */
+ public boolean isTypeInComponent(String canonicalType, String component) {
+
+ return canonicalType.matches(String.format("%1$s.[A-Za-z0-9]+(<.*)?", component));
+ }
+
+ /**
+ * Determines the ID getter for a given 'field' dependent on whether the getter should access the ID via an object
+ * reference or a direct ID getter
+ *
+ * @param field the field
+ * @param byObjectReference boolean
+ * @param component the devon4j component name
+ * @return 'get' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)} + '()' with
+ * capitalize=true
+ */
+ public String resolveIdGetter(Map field, boolean byObjectReference, String component) {
+
+ // If field comes from an UML file
+ if (field.getClass().toGenericString().contains("freemarker.ext.beans.HashAdapter")) {
+ DeferredElementNSImpl umlNode = (DeferredElementNSImpl) field;
+ return resolveIdGetter(umlNode, byObjectReference, component);
+ }
+ return "get" + resolveIdVariableNameOrSetterGetterSuffix(field, byObjectReference, true, component) + "()";
+ }
+
+ /**
+ * Determines the ID getter for a given 'field' dependent on whether the getter should access the ID via an object
+ * reference or a direct ID getter
+ *
+ * This method is used when the field parameter comes from an UML file. The name and type of the attributes must be
+ * pre-processed for later inserting them inside the HashMap.
+ *
+ * @param field the field
+ * @param byObjectReference boolean
+ * @param component the devon4j component name
+ * @return 'get' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)} + '()' with
+ * capitalize=true
+ */
+ public String resolveIdGetter(DeferredElementNSImpl field, boolean byObjectReference, String component) {
+
+ HashMap nodeHash = new HashMap<>();
+
+ // Putting the name of the attribute to the hash
+ nodeHash.put(Field.NAME.toString(), field.getAttribute("name"));
+
+ // Putting the type of the attribute to the hash
+ NodeList childs = field.getChildNodes();
+ for (int i = 0; i < childs.getLength(); i++) {
+ // Retrieve "type" tag
+ if (childs.item(i).getNodeName().equals("type")) {
+ NamedNodeMap attrs = childs.item(i).getAttributes();
+ for (int j = 0; j < attrs.getLength(); j++) {
+ Attr attribute = (Attr) attrs.item(j);
+ // Try to find the attribute that contains the type
+ if (attribute.getName().equals("xmi:idref")) {
+ nodeHash.put(Field.TYPE.toString(), attribute.getName().replace("EAJava_", ""));
+ }
+ }
+ }
+ }
+ return "get" + resolveIdVariableNameOrSetterGetterSuffix(nodeHash, byObjectReference, true, component) + "()";
+
+ }
+
+ /**
+ * Determines the ID getter for a given 'field' dependent on whether the getter should access the ID via an object
+ * reference or a direct ID getter
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldMap the field mapping
+ * @param byObjectReference boolean
+ * @param component the devon4j component name
+ * @return 'get' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)} + '()' with
+ * capitalize=true
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdGetter(Class> pojoClass, Map fieldMap, boolean byObjectReference,
+ String component) throws NoSuchFieldException, SecurityException {
+
+ return "get" + resolveIdVariableNameOrSetterGetterSuffix(pojoClass, fieldMap, byObjectReference, true, component)
+ + "()";
+ }
+
+ /**
+ * same as {@link #resolveIdGetter(Map, boolean, String)} but with byObjectReference=false and component=""
+ *
+ * @param field the field
+ * @return 'get' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map,boolean,boolean,String)} + '()' with
+ * capitalize=true
+ */
+ public String resolveIdGetter(Map field) {
+
+ return this.resolveIdGetter(field, false, "");
+ }
+
+ /**
+ * same as {@link #resolveIdGetter(Class,Map,boolean,String)} but with byObjectReference=false and component=""
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldMap the field mapping
+ * @return 'get' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map,boolean,boolean,String)} + '()' with
+ * capitalize=true
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdGetter(Class> pojoClass, Map fieldMap)
+ throws NoSuchFieldException, SecurityException {
+
+ return resolveIdGetter(pojoClass, fieldMap, false, "");
+ }
+
+ /**
+ * Determines the ID setter for a given 'field' dependent on whether the setter should access the ID via an object
+ * reference or a direct ID setter. In contrast to resolveIdGetter, this function does not generate the function
+ * parenthesis to enable parameter declaration.
+ *
+ * @param field the field
+ * @param byObjectReference boolean
+ * @param component the devon4j component name
+ * @return 'set' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)} with
+ * capitalize=true
+ */
+ public String resolveIdSetter(Map field, boolean byObjectReference, String component) {
+
+ return "set" + resolveIdVariableNameOrSetterGetterSuffix(field, byObjectReference, true, component);
+ }
+
+ /**
+ * same as {@link #resolveIdSetter(Map, boolean, String)} but with byObjectReference=false and component=""
+ *
+ * @param field the field
+ * @return 'set' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)} with
+ * capitalize=true
+ */
+ public String resolveIdSetter(Map field) {
+
+ return this.resolveIdSetter(field, false, "");
+ }
+
+ /**
+ * Determines the ID setter for a given 'field' dependent on whether the setter should access the ID via an object
+ * reference or a direct ID setter. In contrast to resolveIdGetter, this function does not generate the function
+ * parenthesis to enable parameter declaration.
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldMap the field mapping
+ * @param byObjectReference boolean
+ * @param component the devon4j component name
+ * @return 'set'+ {@link #resolveIdVariableNameOrSetterGetterSuffix(Map,boolean,boolean,String)} with capitalize=true
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdSetter(Class> pojoClass, Map fieldMap, boolean byObjectReference,
+ String component) throws NoSuchFieldException, SecurityException {
+
+ return "set" + resolveIdVariableNameOrSetterGetterSuffix(pojoClass, fieldMap, byObjectReference, true, component);
+ }
+
+ /**
+ * same as {@link #resolveIdSetter(Class,Map,boolean,String)} but with byObjectReference=false and component=""
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldMap the field mapping
+ * @return 'set' + {@link #resolveIdVariableNameOrSetterGetterSuffix(Map,boolean,boolean,String)} with capitalize=true
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdSetter(Class> pojoClass, Map fieldMap)
+ throws NoSuchFieldException, SecurityException {
+
+ return resolveIdSetter(pojoClass, fieldMap, false, "");
+ }
+
+ /**
+ * Determines the variable name for the id value of the 'field'
+ *
+ * @param field the field
+ * @return {@link #resolveIdVariableNameOrSetterGetterSuffix(Map, boolean, boolean, String)}) with
+ * byObjectReference=false, capitalize=false and component=""
+ */
+ public String resolveIdVariableName(Map field) {
+
+ // the component is passed down as an empty string since byObjectReference is false and therefore the
+ // component is
+ // never touched
+ return resolveIdVariableNameOrSetterGetterSuffix(field, false, false, "");
+ }
+
+ /**
+ * Determines the variable name for the id value of the specified field in the pojo
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldMap the field mapping
+ * @return {@link #resolveIdVariableNameOrSetterGetterSuffix(Class, Map, boolean, boolean, String)}) with
+ * byObjectReference=false, capitalize=false and component=""
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdVariableName(Class> pojoClass, Map fieldMap)
+ throws NoSuchFieldException, SecurityException {
+
+ // the component is passed down as an empty string since byObjectReference is false and therefore the
+ // component is
+ // never touched
+ return resolveIdVariableNameOrSetterGetterSuffix(pojoClass, fieldMap, false, false, "");
+ }
+
+ /**
+ * Determines the ID setter/getter suffix for a given 'field' dependent on whether the setter/getter should access the
+ * ID via an object reference or a direct ID setter/getter
+ *
+ * @param field the field
+ * @param byObjectReference boolean
+ * @param capitalize if the field name should be capitalized
+ * @param component the devon4j component. Only needed if $byObjectReference is true
+ * @return idVariable name or getter/setter suffix
+ */
+ public String resolveIdVariableNameOrSetterGetterSuffix(Map field, boolean byObjectReference,
+ boolean capitalize, String component) {
+
+ String fieldName = (String) field.get(Field.NAME.toString());
+ if (capitalize) {
+ fieldName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
+ }
+ String suffix = "";
+
+ String fieldType = (String) field.get(Field.TYPE.toString());
+ String fieldCType = (String) field.get(Field.CANONICAL_TYPE.toString());
+ if (fieldType.contains("Entity")) {
+ if (fieldCType.startsWith("java.util.List") || fieldCType.startsWith("java.util.Set")) {
+ suffix = "Ids";
+ if (fieldName.endsWith("s")) {
+ // Assume trailing 's' as indicator for a plural
+ fieldName = fieldName.substring(0, fieldName.length() - 1);
+ }
+ } else {
+ suffix = "Id";
+ }
+ if (byObjectReference && isTypeInComponent(fieldCType, component)) {
+ // direct references for Entities in same component, so get id of the object reference
+ suffix = "().getId";
+ }
+ }
+
+ return fieldName + suffix;
+
+ }
+
+ /**
+ * Determines the ID setter/getter suffix for a given 'field' dependent on whether the setter/getter should access the
+ * ID via an object reference or a direct ID setter/getter
+ *
+ * @param pojoClass the {@link Class} object of the pojo
+ * @param fieldMap the field mapping
+ * @param byObjectReference boolean
+ * @param capitalize if the field name should be capitalized
+ * @param component the devon4j component. Only needed if byObjectReference is true
+ * @return idVariable name or getter/setter suffix
+ * @throws NoSuchFieldException indicating a severe problem in the used model
+ * @throws SecurityException if the field cannot be accessed for any reason
+ */
+ public String resolveIdVariableNameOrSetterGetterSuffix(Class> pojoClass, Map fieldMap,
+ boolean byObjectReference, boolean capitalize, String component) throws NoSuchFieldException, SecurityException {
+
+ String resultName = (String) fieldMap.get(Field.NAME.toString());
+ if (capitalize) {
+ resultName = resultName.substring(0, 1).toUpperCase() + resultName.substring(1);
+ }
+ String suffix = "";
+ String fieldType = (String) fieldMap.get(Field.TYPE.toString());
+ String fieldName = (String) fieldMap.get(Field.NAME.toString());
+ if (fieldType.contains("Entity")) {
+ if (Collection.class.isAssignableFrom(pojoClass.getDeclaredField(fieldName).getType())) {
+ suffix = "Ids";
+ if (resultName.endsWith("s")) {
+ // Assume trailing 's' as indicator for a plural
+ resultName = resultName.substring(0, resultName.length() - 1);
+ }
+ } else {
+ suffix = "Id";
+ }
+ if (byObjectReference
+ && isEntityInComponent(pojoClass.getDeclaredField(fieldName).getType().getName(), component)) {
+ // direct references for Entities in same component, so get id of the object reference
+ suffix = "().getId";
+ }
+ }
+
+ return resultName + suffix;
+
+ }
+
+ /**
+ * Returns the argument type of the list or set from a field. If the string contains "Entity" it will remove that
+ * part. For example, if we have a List <SampleEntity> it will return "Sample"
+ *
+ * @param field the field
+ * @param pojoClass the object class of the Entity that contains the field
+ * @return fieldType argument of the list
+ * @throws SecurityException if field type could not accessed
+ * @throws NoSuchFieldException if field could not be found
+ */
+ public String getListArgumentType(Map field, Class> pojoClass)
+ throws NoSuchFieldException, SecurityException {
+
+ JavaUtil javaUtil = new JavaUtil();
+
+ String fieldType = (String) field.get(Field.TYPE.toString());
+ String fieldName = (String) field.get(Field.NAME.toString());
+
+ if (fieldType.contains("Entity")) {
+ if (javaUtil.isCollection(pojoClass, fieldName)) {
+
+ fieldType = fieldType.replace("Entity", "");
+ // Regex: Extracts the argument type of the list 'List' => type
+ String regex = "(?<=\\<).+?(?=\\>)";
+ Pattern pattern = Pattern.compile(regex);
+ Matcher regexMatcher = pattern.matcher(fieldType);
+
+ if (regexMatcher.find()) {
+ fieldType = regexMatcher.group(0);
+ }
+ }
+ }
+ return fieldType;
+
+ }
+
+ /**
+ * Converts all occurrences of devon4j Entity types in the given 'field' simple type (possibly generic) to Longs
+ *
+ * @param field the field
+ * @return the field type as String. If field type contains 'Entity' the result is Long
+ */
+ public String getSimpleEntityTypeAsLongReference(Map field) {
+
+ String fieldType = (String) field.get(Field.TYPE.toString());
+ if (fieldType.endsWith("Entity")) {
+ fieldType = fieldType.replaceAll("[^<>]+Entity", "Long");
+ }
+ return fieldType;
+ }
+
+ /**
+ * If the string last character is an 's', then it gets removed
+ *
+ * @param targetClassName string to remove plural
+ * @return string without 's'
+ */
+ public String removePlural(String targetClassName) {
+
+ if (targetClassName.charAt(targetClassName.length() - 1) == 's') {
+ targetClassName = targetClassName.substring(0, targetClassName.length() - 1);
+ }
+ return targetClassName;
+ }
+
+ /**
+ * Checks whether the operation with the given ID corresponds to any standard CRUD method name.
+ *
+ * @param operationId operation ID interpreted as method name
+ * @param entityName entity name to check standard CRUD methods for
+ * @return true
if the operation ID maps any standard CRUD method name, false
otherwise
+ */
+ public boolean isCrudOperation(String operationId, String entityName) {
+
+ if (operationId == null) {
+ return false;
+ }
+ String opIdLowerCase = operationId.toLowerCase();
+ String entityNameLowerCase = entityName.toLowerCase();
+ if (opIdLowerCase.contains(entityNameLowerCase)) {
+ return opIdLowerCase.equals("find" + entityNameLowerCase)
+ || opIdLowerCase.equals("find" + entityNameLowerCase + "Etos")
+ || opIdLowerCase.equals("delete" + entityNameLowerCase) || opIdLowerCase.equals("save" + entityNameLowerCase);
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Converts the given media type to the spring Java enum value
+ *
+ * @param mediaType to be converted
+ * @return the spring enum value representing the given media type
+ */
+ public String getSpringMediaType(String mediaType) {
+
+ switch (mediaType) {
+ case "application/xml":
+ return "APPLICATION_XML_VALUE";
+ case "application / x-www-form-urlencoded":
+ return "APPLICATION_FORM_URLENCODED_VALUE";
+ case "multipart/form-data":
+ return "MULTIPART_FORM_DATA_VALUE";
+ case "text/plain":
+ return "TEXT_PLAIN_VALUE";
+ case "text/html":
+ return "TEXT_HTML_VALUE";
+ case "application/pdf":
+ return "APPLICATION_PDF_VALUE";
+ case "image/png":
+ return "IMAGE_PNG_VALUE";
+ default:
+ return "APPLICATION_JSON_VALUE";
+ }
+ }
+}
\ No newline at end of file
diff --git a/cobigen-templates/crud-openapi-net/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java b/cobigen-templates/crud-openapi-net/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java
new file mode 100644
index 0000000000..ced2f5fde2
--- /dev/null
+++ b/cobigen-templates/crud-openapi-net/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java
@@ -0,0 +1,464 @@
+package com.devonfw.cobigen.templates.devon4j.utils;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.commons.lang3.ClassUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Provides type operations, mainly checks and casts for Java Primitives, to be used in the templates
+ *
+ */
+public class JavaUtil {
+
+ /**
+ * Logger for this class
+ */
+ private static final Logger LOG = LoggerFactory.getLogger(JavaUtil.class);
+
+ /**
+ * The constructor.
+ */
+ public JavaUtil() {
+
+ // Empty for CobiGen to automatically instantiate it
+ }
+
+ /**
+ * Returns the Object version of a Java primitive or the input if the input isn't a java primitive
+ *
+ * @param simpleType String
+ * @return the corresponding object wrapper type simple name of the input if the input is the name of a primitive java
+ * type. The input itself if not. (e.g. "int" results in "Integer")
+ * @throws ClassNotFoundException should not occur.
+ */
+ public String boxJavaPrimitives(String simpleType) throws ClassNotFoundException {
+
+ if (equalsJavaPrimitive(simpleType)) {
+ return ClassUtils.primitiveToWrapper(ClassUtils.getClass(simpleType)).getSimpleName();
+ } else {
+ return simpleType;
+ }
+
+ }
+
+ /**
+ * Returns the simple name of the type of a field in the pojoClass. If the type is a java primitive the name of the
+ * wrapper class is returned
+ *
+ * @param pojoClass {@link Class} the class object of the pojo
+ * @param fieldName {@link String} the name of the field
+ * @return String. The simple name of the field's type. The simple name of the wrapper class in case of java
+ * primitives
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public String boxJavaPrimitives(Class> pojoClass, String fieldName) throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+
+ if (equalsJavaPrimitive(pojoClass, fieldName)) {
+ return ClassUtils.primitiveToWrapper(pojoClass.getDeclaredField(fieldName).getType()).getSimpleName();
+ } else {
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ throw new IllegalAccessError("Could not find field " + fieldName + " in class " + pojoClass);
+ } else {
+ return field.getType().getSimpleName();
+ }
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive
+ *
+ * @param simpleType the type to be checked
+ * @return true iff simpleType is a Java primitive
+ */
+ public boolean equalsJavaPrimitive(String simpleType) {
+
+ try {
+ return ClassUtils.getClass(simpleType).isPrimitive();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive or wrapper
+ *
+ * @param simpleType the type to be checked
+ * @return true iff simpleType is a Java primitive or wrapper
+ */
+ public boolean equalsJavaPrimitiveOrWrapper(String simpleType) {
+
+ try {
+ return ClassUtils.isPrimitiveOrWrapper(ClassUtils.getClass(simpleType));
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the type of the field in the pojo's class is a java primitive
+ *
+ * @param pojoClass the {@link Class} object of the pojo
+ * @param fieldName the name of the field to be checked
+ * @return true iff the field is a java primitive
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean equalsJavaPrimitive(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ return false;
+ }
+
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ return false;
+ } else {
+ return field.getType().isPrimitive();
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive or a Java primitive array
+ *
+ * @param simpleType the Type name to be checked
+ * @return true iff {@link #equalsJavaPrimitive(String)} is true or if simpleType is an array with a primitive
+ * component
+ */
+ public boolean equalsJavaPrimitiveIncludingArrays(String simpleType) {
+
+ Class> klasse;
+
+ try {
+ klasse = ClassUtils.getClass(simpleType).getComponentType();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ return equalsJavaPrimitive(simpleType) || (klasse != null && klasse.isPrimitive());
+ }
+
+ /**
+ * Checks if the given field in the pojo class is a java primitive or an array of java primitives
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldName the name of the field to be checked
+ * @return true iff {@link #equalsJavaPrimitive(Class, String)} is true or the field is an array of primitives
+ * @throws NoSuchFieldException indicating something awfully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean equalsJavaPrimitiveIncludingArrays(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ return equalsJavaPrimitive(pojoClass, fieldName) || (pojoClass.getDeclaredField(fieldName).getType().isArray()
+ && pojoClass.getDeclaredField(fieldName).getType().getComponentType().isPrimitive());
+ }
+
+ /**
+ * Returns a cast statement for a given (java primitive, variable name) pair or nothing if the type isn't a java
+ * primitive
+ *
+ * @param simpleType Java Type
+ * @param varName Variable name
+ * @return String either of the form '((Java Primitive Object Type)varName)' if simpleType is a primitive or the empty
+ * String otherwise
+ * @throws ClassNotFoundException should not occur
+ */
+ public String castJavaPrimitives(String simpleType, String varName) throws ClassNotFoundException {
+
+ if (equalsJavaPrimitive(simpleType)) {
+ return String.format("((%1$s)%2$s)", boxJavaPrimitives(simpleType), varName);
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * Returns a cast statement for a given (java primitive, variable name) pair or nothing if the type isn't a java
+ * primitive
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldName the name of the field to be casted
+ * @return if fieldName points to a primitive field then a casted statement (e.g. for an int field:
+ * '((Integer)field)') or an empty String otherwise
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public String castJavaPrimitives(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ if (equalsJavaPrimitive(pojoClass, fieldName)) {
+ return String.format("((%1$s)%2$s)", boxJavaPrimitives(pojoClass, fieldName), fieldName);
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * @param pojoClass {@link Class} the class object of the pojo
+ * @param fieldName {@link String} the name of the field
+ * @return true if the field is an instance of java.utils.Collections
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean isCollection(Class> pojoClass, String fieldName) throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ return false;
+ }
+
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ return false;
+ } else {
+ return Collection.class.isAssignableFrom(field.getType());
+ }
+
+ }
+
+ /**
+ * Returns the Ext Type to a given java type
+ *
+ * @param simpleType any java type's simple name
+ * @return corresponding Ext type
+ */
+ public String getExtType(String simpleType) {
+
+ switch (simpleType) {
+ case "short":
+ case "Short":
+ case "int":
+ case "Integer":
+ case "long":
+ case "Long":
+ return "Integer";
+ case "float":
+ case "Float":
+ case "double":
+ case "Double":
+ return "Number";
+ case "boolean":
+ case "Boolean":
+ return "Boolean";
+ case "char":
+ case "Character":
+ case "String":
+ return "String";
+ case "Date":
+ return "Date";
+ default:
+ return "Field";
+ }
+ }
+
+ /**
+ * returns the Angular5 type associated with a Java primitive
+ *
+ * @param simpleType :{@link String} the type to be parsed
+ * @return the corresponding Angular type or 'any' otherwise
+ */
+ public String getAngularType(String simpleType) {
+
+ switch (simpleType) {
+ case "boolean":
+ return "boolean";
+ case "Boolean":
+ return "boolean";
+ case "short":
+ return "number";
+ case "Short":
+ return "number";
+ case "int":
+ return "number";
+ case "Integer":
+ return "number";
+ case "long":
+ return "number";
+ case "Long":
+ return "number";
+ case "float":
+ return "number";
+ case "Float":
+ return "number";
+ case "double":
+ return "number";
+ case "Double":
+ return "number";
+ case "char":
+ return "string";
+ case "Character":
+ return "string";
+ case "String":
+ return "string";
+ case "byte":
+ return "number";
+ default:
+ return "any";
+ }
+ }
+
+ /**
+ * returns the class name of the return type of a specific method.
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName {@link String} the name of the method
+ * @return the class name of the return type of the specified method
+ * @throws SecurityException If no method of the given name can be found
+ * @throws NoSuchMethodException If no method of the given name can be found
+ */
+ public String getReturnType(Class> pojoClass, String methodName) throws NoSuchMethodException, SecurityException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+ String s = "-";
+ Method method = findMethod(pojoClass, methodName);
+ if (method != null && !method.getReturnType().equals(Void.TYPE)) {
+ s = method.getReturnType().toString();
+ s = s.substring(s.lastIndexOf('.') + 1, s.length());
+ }
+ return s;
+ }
+
+ /**
+ *
+ * This methods returns the return type of the method in the given pojoClass which are annotated with the parameter
+ * annotatedClass
+ *
+ * @param pojoClass - The class in which to find if it has methods with annotatedClass
+ * @param annotatedClassName - The annotation which needs to be found
+ * @return Return type of the method annotated with the given annotation, else "null"
+ * @throws ClassNotFoundException if the annotated class name could not be found in the class path
+ */
+ @SuppressWarnings("unchecked")
+ public String getReturnTypeOfMethodAnnotatedWith(Class> pojoClass, String annotatedClassName)
+ throws ClassNotFoundException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+
+ Method[] methods = pojoClass.getDeclaredMethods();
+ for (Method method : methods) {
+ if (!method.getName().startsWith("get")) {
+ continue;
+ }
+ for (Annotation a : method.getAnnotations()) {
+ // better if (method.isAnnotationPresent(classObj)) {, but postponed as of different class
+ // loaders of a.getClass() and pojoClass.getClass()
+ if (a.getClass().getCanonicalName().equals(annotatedClassName)) {
+ return method.getReturnType().getSimpleName();
+ }
+ }
+ }
+ return "null";
+ }
+
+ /**
+ * returns the HTTP request type corresponding to an annotation type
+ *
+ * @param annotations The annotation to get the type name of
+ * @return the HTTP request type name of the selected annotation
+ */
+ public String getRequestType(Map annotations) {
+
+ if (annotations.containsKey("javax_ws_rs_GET")) {
+ return "GET";
+ } else if (annotations.containsKey("javax_ws_rs_PUT")) {
+ return "PUT";
+ } else if (annotations.containsKey("javax_ws_rs_POST")) {
+ return "POST";
+ } else if (annotations.containsKey("javax_ws_rs_DELETE")) {
+ return "DELETE";
+ } else if (annotations.containsKey("javax_ws_rs_PATCH")) {
+ return "PATCH";
+ } else {
+ return "-";
+ }
+ }
+
+ /**
+ * Helper method to find a class's specific method
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName The name of the method to be found
+ * @return The method object of the method to be found, null if it wasn't found
+ */
+ private Method findMethod(Class> pojoClass, String methodName) {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+ for (Method m : pojoClass.getMethods()) {
+ if (m.getName().equals(methodName)) {
+ return m;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Checks whether the class given by the full qualified name is an enum
+ *
+ * @param className full qualified class name
+ * @return true
if the class is an enum, false
otherwise
+ */
+ public boolean isEnum(String className) {
+
+ try {
+ return ClassUtils.getClass(className).isEnum();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), className);
+ return false;
+ }
+ }
+
+ /**
+ * Returns the first enum value of an enum class
+ *
+ * @param className full qualified class name
+ * @return the first enum value name found in order
+ */
+ public String getFirstEnumValue(String className) {
+
+ try {
+ Class> enumClass = ClassUtils.getClass(className);
+ Field[] declaredFields = enumClass.getDeclaredFields();
+ if (declaredFields.length > 0) {
+ return declaredFields[0].getName();
+ } else {
+ return null;
+ }
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), className);
+ return null;
+ }
+ }
+}
diff --git a/cobigen-templates/crud-openapi-net/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/OpenApiUtil.java b/cobigen-templates/crud-openapi-net/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/OpenApiUtil.java
new file mode 100644
index 0000000000..a93288f45a
--- /dev/null
+++ b/cobigen-templates/crud-openapi-net/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/OpenApiUtil.java
@@ -0,0 +1,255 @@
+package com.devonfw.cobigen.templates.devon4j.utils;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+
+/** Utils on OpenAPI template model */
+public class OpenApiUtil {
+
+ /**
+ * Prints javax validation constraints from an OpenAPI model
+ *
+ * @param constraints OpenAPI model constraints
+ * @return the list of supported annotations in Java syntax
+ */
+ public String printJavaConstraints(Map constraints) {
+
+ String consts = "";
+ if (constraints.get("maximum") != null) {
+ consts = consts + "@Max(" + constraints.get("maximum") + ")";
+ }
+ if (constraints.get("minimum") != null) {
+ consts = consts + "@Min(" + constraints.get("minimum") + ")";
+ }
+ if (constraints.get("maxLength") != null) {
+ consts = consts + "@Size(max=" + constraints.get("maxLength");
+ if (constraints.get("minLength") != null) {
+ consts = consts + ", min=" + constraints.get("minLength");
+ }
+ consts = consts + ")";
+ } else {
+ if (constraints.get("minLength") != null) {
+ consts = consts + "@Size(min=" + constraints.get("minLength");
+ if (constraints.get("maxLength") != null) {
+ consts = consts + ", max=" + constraints.get("maxLength");
+ }
+ consts = consts + ")";
+ }
+ }
+ return consts;
+ }
+
+ /**
+ * Prints the return type of a response based on the OpenAPI model
+ *
+ * @param response the OpenAPI model of a response
+ * @return simple type of the response return type in Java syntax
+ */
+ public String printJavaServiceResponseReturnType(Map response) {
+
+ String returnType = toJavaType(response, false);
+ if ((boolean) response.get("isVoid")) {
+ return "void";
+ }
+ if ((boolean) response.get("isArray")) {
+ if ((boolean) response.get("isEntity")) {
+ if (returnType.contains("Entity")) {
+ return "List<" + returnType + ">";
+ } else {
+ return "List<" + returnType + "Entity>";
+ }
+ } else {
+ return "List<" + returnType + ">";
+ }
+ } else if ((boolean) response.get("isPaginated")) {
+ if ((boolean) response.get("isEntity")) {
+ if (returnType.contains("Entity")) {
+ return "Page<" + returnType + ">";
+ } else {
+ return "Page<" + returnType + "Entity>";
+ }
+ } else {
+ return "Page<" + returnType + ">";
+ }
+ } else {
+ return returnType;
+ }
+ }
+
+ /**
+ * Returns the Java type corresponding to the OpenAPI type definition. If the type could not be matched, Object will
+ * be returned.
+ *
+ * @param parameter OpenAPI model of a parameter
+ * @param simpleType if a Java simple type should be returned if possible
+ * @return the Java type
+ */
+ public String toJavaType(Map parameter, boolean simpleType) {
+
+ String typeConverted = null;
+ String format = (String) parameter.get("format");
+ String type = (String) parameter.get("type");
+ boolean isCollection = false;
+ if (parameter.get("isCollection") != null) {
+ isCollection = (boolean) parameter.get("isCollection");
+ }
+
+ boolean isEntity = (boolean) parameter.get("isEntity");
+
+ if (type != null) {
+ switch (type.toLowerCase()) {
+ case "integer":
+ if (format != null) {
+ switch (format) {
+ case "int32":
+ typeConverted = simpleType ? "int" : "Integer";
+ break;
+ case "int64":
+ typeConverted = simpleType ? "long" : "Long";
+ break;
+ default:
+ typeConverted = BigInteger.class.getSimpleName();
+ break;
+ }
+ } else {
+ typeConverted = BigInteger.class.getSimpleName();
+ }
+ break;
+ case "number":
+ if (format != null) {
+ switch (format) {
+ case "float":
+ typeConverted = simpleType ? "float" : "Float";
+ break;
+ case "double":
+ typeConverted = simpleType ? "double" : "Double";
+ break;
+ default:
+ typeConverted = BigDecimal.class.getSimpleName();
+ break;
+ }
+ } else {
+ typeConverted = BigDecimal.class.getSimpleName();
+ }
+ break;
+ case "string":
+ if (format != null) {
+ switch (format) {
+ case "date":
+ typeConverted = LocalDate.class.getSimpleName();
+ break;
+ case "date-time":
+ typeConverted = Instant.class.getSimpleName();
+ break;
+ case "binary":
+ typeConverted = simpleType ? "float" : "Float";
+ break;
+ case "email":
+ case "password":
+ typeConverted = String.class.getSimpleName();
+ break;
+ default:
+ typeConverted = "String";
+ break;
+ }
+ } else {
+ typeConverted = "String";
+ }
+ break;
+ case "boolean":
+ typeConverted = simpleType ? "boolean" : "Boolean";
+ break;
+ default:
+ typeConverted = "void";
+ break;
+ }
+ } else {
+ typeConverted = "void";
+ }
+
+ if (isCollection) {
+ if (isEntity) {
+ return "List<" + parameter.get("type") + ">";
+ } else {
+ return "List<" + typeConverted + ">";
+ }
+ } else if (isEntity) {
+ return (String) parameter.get("type");
+ }
+ return typeConverted;
+ }
+
+ /**
+ * Returns the TypeScript type corresponding to the OpenAPI type definition. If the type could not be matched, the
+ * same value will be returned.
+ *
+ * @param parameter OpenAPI model of a parameter
+ * @return the Java type
+ */
+ // getOaspTypeFromOpenAPI
+ public String toTypeScriptType(Map parameter) {
+
+ String typeConverted = null;
+ String type = (String) parameter.get("type");
+ boolean isCollection = false;
+ if (parameter.get("isCollection") != null) {
+ isCollection = (boolean) parameter.get("isCollection");
+ }
+
+ boolean isEntity = (boolean) parameter.get("isEntity");
+
+ if (type != null) {
+ switch (type.toLowerCase()) {
+ case "integer":
+ typeConverted = "number";
+ break;
+ default:
+ typeConverted = type;
+ break;
+ }
+ } else {
+ typeConverted = "undefined";
+ }
+
+ if (isCollection) {
+ if (isEntity) {
+ return parameter.get("type") + "[]";
+ } else {
+ return typeConverted + "[]";
+ }
+ } else if (isEntity) {
+ return (String) parameter.get("type");
+ }
+ return typeConverted;
+ }
+
+ /**
+ * Prints the service operation name based on the operationId or generates one based on the servicePath while printing
+ * a comment how to get better service names.
+ *
+ * @param operation operation Model of the OpenAPI model
+ * @param servicePath service path of the
+ * @return the service method name
+ */
+ public String printServiceOperationName(Map operation, String servicePath) {
+
+ String operationId = (String) operation.get("operationId");
+ if (StringUtils.isEmpty(operationId)) {
+ String[] split = servicePath.split("/");
+ String lastSegment;
+ if (!split[split.length - 1].isEmpty()) {
+ lastSegment = split[split.length - 1];
+ } else {
+ lastSegment = split[split.length - 2];
+ }
+ return ((String) operation.get("type")) + lastSegment;
+ } else {
+ return operationId;
+ }
+ }
+}
diff --git a/cobigen-templates/kafka-documentation/pom.xml b/cobigen-templates/kafka-documentation/pom.xml
index 9e494624e3..fc496c637a 100644
--- a/cobigen-templates/kafka-documentation/pom.xml
+++ b/cobigen-templates/kafka-documentation/pom.xml
@@ -10,4 +10,15 @@
${revision}
+
+
+ javax.ws.rs
+ javax.ws.rs-api
+ 2.0
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
\ No newline at end of file
diff --git a/cobigen-templates/kafka-documentation/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/documentation/JavaDocumentationUtil.java b/cobigen-templates/kafka-documentation/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/documentation/JavaDocumentationUtil.java
new file mode 100644
index 0000000000..8832368645
--- /dev/null
+++ b/cobigen-templates/kafka-documentation/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/documentation/JavaDocumentationUtil.java
@@ -0,0 +1,346 @@
+package com.devonfw.cobigen.templates.devon4j.utils.documentation;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+
+/**
+ *
+ */
+public class JavaDocumentationUtil {
+
+ /** Full qualified name of spring RequestMapping annotation */
+ private final String requestMapping = "org_springframework_web_bind_annotation_RequestMapping";
+
+ /** Full qualified name of javax Path annotation */
+ private final String javaxPath = "javax_ws_rs_Path";
+
+ /**
+ * Creates a list of parameters of a specific method as an asciidoc string, including its name, type, description,
+ * constraints
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName {@link String} the name of the method to get the parameter info of
+ * @param javaDoc the javadoc of the method, taken from the javaplugin model
+ * @return A list of the parameters info in asciidoc code
+ * @throws Exception When errors occur in invoking an annotations method
+ */
+ public String getParams(Class> pojoClass, String methodName, Map javaDoc) throws Exception {
+
+ String result = "";
+ Method m = findMethod(pojoClass, methodName);
+ if (m.getParameterCount() < 1) {
+ return "!-!-!-!-";
+ }
+ if (m.getParameterCount() == 1) {
+ if (!m.getParameters()[0].getType().isPrimitive()) {
+ return "!-!-!-!-";
+ }
+ }
+ for (Parameter param : m.getParameters()) {
+ // Add the name of the parameter as path or query parameter
+ boolean isPath = param.isAnnotationPresent(javax.ws.rs.PathParam.class);
+ boolean isQuery = param.isAnnotationPresent(javax.ws.rs.QueryParam.class);
+ if (isPath || isQuery) {
+ result += "!";
+ if (isPath) {
+ result += "{" + param.getAnnotation(javax.ws.rs.PathParam.class).value() + "}" + System.lineSeparator();
+ } else if (isQuery) {
+ result += "?" + param.getAnnotation(javax.ws.rs.QueryParam.class).value() + System.lineSeparator();
+ }
+
+ // Add the type
+ String type = param.getType().getSimpleName();
+ result += "!" + type + System.lineSeparator();
+
+ // Add the constraints
+ result += "!";
+ int counter = 0;
+ for (Annotation anno : param.getAnnotations()) {
+ String annoName = anno.annotationType().getName();
+ Pattern p = Pattern.compile("javax\\.validation\\.constraints\\.([^\\.]*)");
+ Matcher match = p.matcher(annoName);
+ if (match.find()) {
+ counter++;
+ String shortName = annoName.substring(annoName.lastIndexOf('.') + 1);
+ Object value;
+ Method method;
+ try {
+ method = anno.getClass().getMethod("value");
+ value = method.invoke(anno);
+ result += shortName + " = " + value + " +" + System.lineSeparator();
+ } catch (NoSuchMethodException e) {
+ result += shortName + " +" + System.lineSeparator();
+ } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
+ | SecurityException e) {
+ throw new Exception(e.getMessage());
+ }
+ }
+ }
+ if (counter == 0) {
+ result += "-" + System.lineSeparator();
+ }
+
+ // Add Javadoc
+ Map params = (Map) javaDoc.get("params");
+ result += "!" + getJavaDocWithoutLink(params.get(param.getName())) + " +" + System.lineSeparator();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * returns the javadoc of an element, stripped of any links to other sources
+ *
+ * @param doc the javadoc to be changed
+ * @return the input string stripped of all links
+ */
+ public String getJavaDocWithoutLink(String doc) {
+
+ Pattern p = Pattern.compile("(\\{@link ([^\\}]*)\\})");
+ Matcher m = p.matcher(doc);
+ while (m.find()) {
+ doc = doc.replace(m.group(1), m.group(2));
+ }
+ return doc;
+ }
+
+ /**
+ * Create a response in JSON format, iterating through non-primitive types to get their data as well
+ *
+ * @param pojoClass The input class
+ * @param methodName The name of the operation to get the response of
+ * @return A JSON representation of the response object
+ * @throws Exception When Jackson fails
+ */
+ public String getJSONResponseBody(Class> pojoClass, String methodName) throws Exception {
+
+ Class> responseType = findMethod(pojoClass, methodName).getReturnType();
+ if (hasBody(pojoClass, methodName, true)) {
+ return getJSON(responseType);
+ }
+ return "-";
+ }
+
+ /**
+ * Create a request in JSON format, iterating through non-primitive types to get their data as well
+ *
+ * @param pojoClass The input class
+ * @param methodName The name of the operation to get the request of
+ * @return A JSON representation of the request object
+ * @throws Exception When Jackson fails
+ */
+ public String getJSONRequestBody(Class> pojoClass, String methodName) throws Exception {
+
+ Method m = findMethod(pojoClass, methodName);
+ if (hasBody(pojoClass, methodName, false)) {
+ Parameter param = m.getParameters()[0];
+ Class> requestType = param.getType();
+ return getJSON(requestType);
+ }
+ return "-";
+ }
+
+ /**
+ * Using Jackson, creates a JSON string for Asciidoc
+ *
+ * @param clazz The class to create the JSON string of
+ * @return A JSON representation of the given class
+ * @throws Exception When Jackson fails
+ */
+ public String getJSON(Class> clazz) throws Exception {
+
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
+ mapper.enable(SerializationFeature.INDENT_OUTPUT);
+ try {
+ Object obj = clazz.newInstance();
+ return "...." + System.lineSeparator() + mapper.writeValueAsString(obj) + System.lineSeparator() + "....";
+ } catch (InstantiationException | IllegalAccessException | JsonProcessingException e) {
+ throw new Exception(e.getMessage());
+ }
+ }
+
+ /**
+ * Checks if a request/response has a body
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName The name of the operation to be checked
+ * @param isResponse true if the response of the operation should be checked, false if the request should be checked
+ * @return true if the response/request has a body, false if not
+ * @throws SecurityException If no method of the given name can be found
+ */
+ public boolean hasBody(Class> pojoClass, String methodName, boolean isResponse) throws SecurityException {
+
+ Method m = findMethod(pojoClass, methodName);
+ if (isResponse) {
+ Class> returnType = m.getReturnType();
+ if (!returnType.isPrimitive() && !returnType.equals(Void.TYPE)) {
+ return true;
+ }
+ } else {
+ int nr = 0;
+ int position = 0;
+ for (Parameter param : m.getParameters()) {
+ if (!param.isAnnotationPresent(javax.ws.rs.PathParam.class)
+ && !param.isAnnotationPresent(javax.ws.rs.QueryParam.class)) {
+ nr++;
+ position = Integer.parseInt(param.getName().replace("arg", ""));
+ }
+ }
+ if (nr == 1) {
+ Parameter param = m.getParameters()[position];
+ Class> requestType = param.getType();
+ if (!requestType.isPrimitive() && !requestType.equals(Void.TYPE)
+ && !param.isAnnotationPresent(javax.ws.rs.PathParam.class)
+ && !param.isAnnotationPresent(javax.ws.rs.QueryParam.class)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * returns the HTTP request type corresponding to an annotation type
+ *
+ * @param annotations The annotation to get the type name of
+ * @return the HTTP request type name of the selected annotation
+ */
+ public String getRequestType(Map annotations) {
+
+ String type = "";
+ if (annotations.containsKey(this.requestMapping)) {
+ Map method = (Map) annotations.get(this.requestMapping);
+ String rm = (String) method.get("method");
+ type = rm.toLowerCase();
+ }
+ if (annotations.containsKey("javax_ws_rs_GET") || type.equals("requestmethod.get")) {
+ return "GET";
+ } else if (annotations.containsKey("javax_ws_rs_PUT") || type.equals("requestmethod.put")) {
+ return "PUT";
+ } else if (annotations.containsKey("javax_ws_rs_POST") || type.equals("requestmethod.post")) {
+ return "POST";
+ } else if (annotations.containsKey("javax_ws_rs_DELETE") || type.equals("requestmethod.delete")) {
+ return "DELETE";
+ } else if (annotations.containsKey("javax_ws_rs_PATCH") || type.equals("requestmethod.patch")) {
+ return "PATCH";
+ } else {
+ return "-";
+ }
+ }
+
+ /**
+ * Gets the path of an operation
+ *
+ * @param pojoAnnotations the annotation map of the given pojo
+ * @param method The method to get the operation path of
+ * @return The path of an operation
+ * @throws IOException If no application_properties file is found
+ */
+ public String getOperationPath(Map pojoAnnotations, Map method) throws IOException {
+
+ String path = getPath(pojoAnnotations);
+ Map pathAnno = new HashMap<>();
+ if (pojoAnnotations.containsKey(this.javaxPath)) {
+ pathAnno = (Map) pojoAnnotations.get(this.javaxPath);
+ } else if (pojoAnnotations.containsKey(this.requestMapping)) {
+ pathAnno = (Map) pojoAnnotations.get(this.requestMapping);
+ }
+ if (pathAnno.containsKey("value")) {
+ String toAdd = (String) pathAnno.get("value");
+ if (toAdd.startsWith("/") && path.endsWith("/")) {
+ path += toAdd.substring(1);
+ }
+ }
+ return path;
+ }
+
+ /**
+ * Gets the path of a component
+ *
+ * @param pojoAnnotations the annotation map of the given pojo
+ * @return The communal path of a component
+ * @throws IOException If no application_properties file is found
+ */
+ public String getPath(Map pojoAnnotations) throws IOException {
+
+ String path = extractRootPath();
+ Map pathAnno = new HashMap<>();
+ if (pojoAnnotations.containsKey(this.javaxPath)) {
+ pathAnno = (Map) pojoAnnotations.get(this.javaxPath);
+ } else if (pojoAnnotations.containsKey(this.requestMapping)) {
+ pathAnno = (Map) pojoAnnotations.get(this.requestMapping);
+ }
+ if (pathAnno.containsKey("value")) {
+ String toAdd = (String) pathAnno.get("value");
+ if (toAdd.startsWith("/") && path.endsWith(":")) {
+ path += toAdd.substring(1);
+ }
+ }
+ return path;
+ }
+
+ /**
+ * Checks the class path for an application.properties file and extracts the port and path from it
+ *
+ * @return The root path of the application
+ * @throws IOException If no application.properties file could be found
+ */
+ private String extractRootPath() throws IOException {
+
+ Class> clazz = this.getClass();
+ String t = "";
+ StringBuilder sb = new StringBuilder("http://localhost:");
+ try (InputStream in = clazz.getClassLoader().getResourceAsStream("application.properties")) {
+ if (in != null) {
+ try (InputStreamReader reader = new InputStreamReader(in); BufferedReader br = new BufferedReader(reader)) {
+ while ((t = br.readLine()) != null) {
+ if (t.matches("server\\.port=(\\d{0,5})") || t.matches("server\\.context-path=([^\\s]*)")) {
+ sb.append(t.substring(t.indexOf('=') + 1));
+ }
+ }
+ return sb.toString();
+ }
+ } else {
+ return "";
+ }
+ }
+ }
+
+ /**
+ * Helper method to find a class's specific method
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName The name of the method to be found
+ * @return The method object of the method to be found, null if it wasn't found
+ */
+ private Method findMethod(Class> pojoClass, String methodName) {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+ for (Method m : pojoClass.getMethods()) {
+ if (m.getName().equals(methodName)) {
+ return m;
+ }
+ }
+ return null;
+ }
+}
diff --git a/cobigen-templates/openapi-documentation/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/documentation/DocumentationUtil.java b/cobigen-templates/openapi-documentation/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/documentation/DocumentationUtil.java
new file mode 100644
index 0000000000..4eda4c9d8e
--- /dev/null
+++ b/cobigen-templates/openapi-documentation/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/documentation/DocumentationUtil.java
@@ -0,0 +1,32 @@
+package com.devonfw.cobigen.templates.devon4j.utils.documentation;
+
+/**
+ *
+ */
+public class DocumentationUtil {
+
+ /**
+ * Creates asciidoc code for colour coded HTTP request types
+ *
+ * @param type the HTTP request type to be coloured
+ * @return the asciidoc code for differently coloured request types, aqua for get, lime for post, red for delete,
+ * yellow for put and fuchsia for patch (HTML colour names)
+ */
+ public String getTypeWithAsciidocColour(String type) {
+
+ switch (type.toLowerCase()) {
+ case "get":
+ return "[aqua]#" + type.toUpperCase() + "#";
+ case "post":
+ return "[lime]#" + type.toUpperCase() + "#";
+ case "delete":
+ return "[red]#" + type.toUpperCase() + "#";
+ case "put":
+ return "[yellow]#" + type.toUpperCase() + "#";
+ case "patch":
+ return "[fuchsia]#" + type.toUpperCase() + "#";
+ default:
+ return "";
+ }
+ }
+}
diff --git a/cobigen-templates/openapi-documentation/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/documentation/OpenApiDocumentationUtil.java b/cobigen-templates/openapi-documentation/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/documentation/OpenApiDocumentationUtil.java
new file mode 100644
index 0000000000..f7d9472b71
--- /dev/null
+++ b/cobigen-templates/openapi-documentation/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/documentation/OpenApiDocumentationUtil.java
@@ -0,0 +1,74 @@
+package com.devonfw.cobigen.templates.devon4j.utils.documentation;
+
+import java.util.Map;
+
+/**
+ *
+ */
+public class OpenApiDocumentationUtil {
+
+ /**
+ * Adds indicators to a parameter name based on them being a ?query or a {path} parameter
+ *
+ * @param param the parameter to add indicators too
+ * @return The name of the given parameter with the prefix ? or surrounded by {}
+ */
+ public String getParam(Map param) {
+
+ String result = "";
+ String type = (String) param.get("type");
+ if (type == null || type.equals("void")) {
+ result = "void";
+ } else {
+ if ((boolean) param.get("inPath")) {
+ result += "{" + type + "}";
+ } else if ((boolean) param.get("inQuery")) {
+ result += "?" + type;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Lists the constraints of an operations parameter as asciidoc code
+ *
+ * @param param The parameter which constraints should be listed
+ * @return The list of constraints as asciidoc code
+ */
+ public String getConstraintList(Map param) {
+
+ String result = "";
+ Map constraints = (Map) param.get("constraints");
+ boolean required = false;
+ int nrParam = 0;
+ if (constraints != null) {
+ if (constraints.containsKey("notNull")) {
+ required = (boolean) constraints.get("notNull");
+ }
+ if (required) {
+ result += "[red]#__Required__# +" + System.lineSeparator();
+ nrParam++;
+ }
+ for (String key : constraints.keySet()) {
+ if (!key.equals("notNull")) {
+ Object val = constraints.get(key);
+ if (val != null) {
+ if (val instanceof Boolean) {
+ if ((boolean) val) {
+ result += key + " +" + System.lineSeparator();
+ nrParam++;
+ }
+ } else {
+ result += key + " = " + val + " +" + System.lineSeparator();
+ nrParam++;
+ }
+ }
+ }
+ }
+ }
+ if (nrParam == 0) {
+ result = "-";
+ }
+ return result;
+ }
+}
diff --git a/cobigen-templates/pom.xml b/cobigen-templates/pom.xml
index 7b34bdad75..24172edfc1 100644
--- a/cobigen-templates/pom.xml
+++ b/cobigen-templates/pom.xml
@@ -14,7 +14,10 @@
../pom.xml
-
+
+ 1.8
+ 1.8
+
templates-devon4j-utils
@@ -54,6 +57,10 @@
src/main/resources
src/main/templates
+
+ src/main/java
+ src/main/java
+
@@ -87,6 +94,13 @@
org.apache.maven.plugins
maven-antrun-plugin
+
+
+ ant-contrib
+ ant-contrib
+ 20020829
+
+
prepare-package
@@ -96,6 +110,29 @@
Integrate flattened POM manually
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </project>
+
+
diff --git a/cobigen-templates/pom_patch.xml b/cobigen-templates/pom_patch.xml
new file mode 100644
index 0000000000..1dc364a9cb
--- /dev/null
+++ b/cobigen-templates/pom_patch.xml
@@ -0,0 +1,4 @@
+
+ {maven.compiler.source}
+ {maven.compiler.source}
+
diff --git a/cobigen-templates/rest-documentation/pom.xml b/cobigen-templates/rest-documentation/pom.xml
index f4b3382438..6d2c790050 100644
--- a/cobigen-templates/rest-documentation/pom.xml
+++ b/cobigen-templates/rest-documentation/pom.xml
@@ -10,4 +10,15 @@
${revision}
+
+
+ javax.ws.rs
+ javax.ws.rs-api
+ 2.0
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
\ No newline at end of file
diff --git a/cobigen-templates/rest-documentation/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/documentation/JavaDocumentationUtil.java b/cobigen-templates/rest-documentation/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/documentation/JavaDocumentationUtil.java
new file mode 100644
index 0000000000..8832368645
--- /dev/null
+++ b/cobigen-templates/rest-documentation/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/documentation/JavaDocumentationUtil.java
@@ -0,0 +1,346 @@
+package com.devonfw.cobigen.templates.devon4j.utils.documentation;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+
+/**
+ *
+ */
+public class JavaDocumentationUtil {
+
+ /** Full qualified name of spring RequestMapping annotation */
+ private final String requestMapping = "org_springframework_web_bind_annotation_RequestMapping";
+
+ /** Full qualified name of javax Path annotation */
+ private final String javaxPath = "javax_ws_rs_Path";
+
+ /**
+ * Creates a list of parameters of a specific method as an asciidoc string, including its name, type, description,
+ * constraints
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName {@link String} the name of the method to get the parameter info of
+ * @param javaDoc the javadoc of the method, taken from the javaplugin model
+ * @return A list of the parameters info in asciidoc code
+ * @throws Exception When errors occur in invoking an annotations method
+ */
+ public String getParams(Class> pojoClass, String methodName, Map javaDoc) throws Exception {
+
+ String result = "";
+ Method m = findMethod(pojoClass, methodName);
+ if (m.getParameterCount() < 1) {
+ return "!-!-!-!-";
+ }
+ if (m.getParameterCount() == 1) {
+ if (!m.getParameters()[0].getType().isPrimitive()) {
+ return "!-!-!-!-";
+ }
+ }
+ for (Parameter param : m.getParameters()) {
+ // Add the name of the parameter as path or query parameter
+ boolean isPath = param.isAnnotationPresent(javax.ws.rs.PathParam.class);
+ boolean isQuery = param.isAnnotationPresent(javax.ws.rs.QueryParam.class);
+ if (isPath || isQuery) {
+ result += "!";
+ if (isPath) {
+ result += "{" + param.getAnnotation(javax.ws.rs.PathParam.class).value() + "}" + System.lineSeparator();
+ } else if (isQuery) {
+ result += "?" + param.getAnnotation(javax.ws.rs.QueryParam.class).value() + System.lineSeparator();
+ }
+
+ // Add the type
+ String type = param.getType().getSimpleName();
+ result += "!" + type + System.lineSeparator();
+
+ // Add the constraints
+ result += "!";
+ int counter = 0;
+ for (Annotation anno : param.getAnnotations()) {
+ String annoName = anno.annotationType().getName();
+ Pattern p = Pattern.compile("javax\\.validation\\.constraints\\.([^\\.]*)");
+ Matcher match = p.matcher(annoName);
+ if (match.find()) {
+ counter++;
+ String shortName = annoName.substring(annoName.lastIndexOf('.') + 1);
+ Object value;
+ Method method;
+ try {
+ method = anno.getClass().getMethod("value");
+ value = method.invoke(anno);
+ result += shortName + " = " + value + " +" + System.lineSeparator();
+ } catch (NoSuchMethodException e) {
+ result += shortName + " +" + System.lineSeparator();
+ } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
+ | SecurityException e) {
+ throw new Exception(e.getMessage());
+ }
+ }
+ }
+ if (counter == 0) {
+ result += "-" + System.lineSeparator();
+ }
+
+ // Add Javadoc
+ Map params = (Map) javaDoc.get("params");
+ result += "!" + getJavaDocWithoutLink(params.get(param.getName())) + " +" + System.lineSeparator();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * returns the javadoc of an element, stripped of any links to other sources
+ *
+ * @param doc the javadoc to be changed
+ * @return the input string stripped of all links
+ */
+ public String getJavaDocWithoutLink(String doc) {
+
+ Pattern p = Pattern.compile("(\\{@link ([^\\}]*)\\})");
+ Matcher m = p.matcher(doc);
+ while (m.find()) {
+ doc = doc.replace(m.group(1), m.group(2));
+ }
+ return doc;
+ }
+
+ /**
+ * Create a response in JSON format, iterating through non-primitive types to get their data as well
+ *
+ * @param pojoClass The input class
+ * @param methodName The name of the operation to get the response of
+ * @return A JSON representation of the response object
+ * @throws Exception When Jackson fails
+ */
+ public String getJSONResponseBody(Class> pojoClass, String methodName) throws Exception {
+
+ Class> responseType = findMethod(pojoClass, methodName).getReturnType();
+ if (hasBody(pojoClass, methodName, true)) {
+ return getJSON(responseType);
+ }
+ return "-";
+ }
+
+ /**
+ * Create a request in JSON format, iterating through non-primitive types to get their data as well
+ *
+ * @param pojoClass The input class
+ * @param methodName The name of the operation to get the request of
+ * @return A JSON representation of the request object
+ * @throws Exception When Jackson fails
+ */
+ public String getJSONRequestBody(Class> pojoClass, String methodName) throws Exception {
+
+ Method m = findMethod(pojoClass, methodName);
+ if (hasBody(pojoClass, methodName, false)) {
+ Parameter param = m.getParameters()[0];
+ Class> requestType = param.getType();
+ return getJSON(requestType);
+ }
+ return "-";
+ }
+
+ /**
+ * Using Jackson, creates a JSON string for Asciidoc
+ *
+ * @param clazz The class to create the JSON string of
+ * @return A JSON representation of the given class
+ * @throws Exception When Jackson fails
+ */
+ public String getJSON(Class> clazz) throws Exception {
+
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
+ mapper.enable(SerializationFeature.INDENT_OUTPUT);
+ try {
+ Object obj = clazz.newInstance();
+ return "...." + System.lineSeparator() + mapper.writeValueAsString(obj) + System.lineSeparator() + "....";
+ } catch (InstantiationException | IllegalAccessException | JsonProcessingException e) {
+ throw new Exception(e.getMessage());
+ }
+ }
+
+ /**
+ * Checks if a request/response has a body
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName The name of the operation to be checked
+ * @param isResponse true if the response of the operation should be checked, false if the request should be checked
+ * @return true if the response/request has a body, false if not
+ * @throws SecurityException If no method of the given name can be found
+ */
+ public boolean hasBody(Class> pojoClass, String methodName, boolean isResponse) throws SecurityException {
+
+ Method m = findMethod(pojoClass, methodName);
+ if (isResponse) {
+ Class> returnType = m.getReturnType();
+ if (!returnType.isPrimitive() && !returnType.equals(Void.TYPE)) {
+ return true;
+ }
+ } else {
+ int nr = 0;
+ int position = 0;
+ for (Parameter param : m.getParameters()) {
+ if (!param.isAnnotationPresent(javax.ws.rs.PathParam.class)
+ && !param.isAnnotationPresent(javax.ws.rs.QueryParam.class)) {
+ nr++;
+ position = Integer.parseInt(param.getName().replace("arg", ""));
+ }
+ }
+ if (nr == 1) {
+ Parameter param = m.getParameters()[position];
+ Class> requestType = param.getType();
+ if (!requestType.isPrimitive() && !requestType.equals(Void.TYPE)
+ && !param.isAnnotationPresent(javax.ws.rs.PathParam.class)
+ && !param.isAnnotationPresent(javax.ws.rs.QueryParam.class)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * returns the HTTP request type corresponding to an annotation type
+ *
+ * @param annotations The annotation to get the type name of
+ * @return the HTTP request type name of the selected annotation
+ */
+ public String getRequestType(Map annotations) {
+
+ String type = "";
+ if (annotations.containsKey(this.requestMapping)) {
+ Map method = (Map) annotations.get(this.requestMapping);
+ String rm = (String) method.get("method");
+ type = rm.toLowerCase();
+ }
+ if (annotations.containsKey("javax_ws_rs_GET") || type.equals("requestmethod.get")) {
+ return "GET";
+ } else if (annotations.containsKey("javax_ws_rs_PUT") || type.equals("requestmethod.put")) {
+ return "PUT";
+ } else if (annotations.containsKey("javax_ws_rs_POST") || type.equals("requestmethod.post")) {
+ return "POST";
+ } else if (annotations.containsKey("javax_ws_rs_DELETE") || type.equals("requestmethod.delete")) {
+ return "DELETE";
+ } else if (annotations.containsKey("javax_ws_rs_PATCH") || type.equals("requestmethod.patch")) {
+ return "PATCH";
+ } else {
+ return "-";
+ }
+ }
+
+ /**
+ * Gets the path of an operation
+ *
+ * @param pojoAnnotations the annotation map of the given pojo
+ * @param method The method to get the operation path of
+ * @return The path of an operation
+ * @throws IOException If no application_properties file is found
+ */
+ public String getOperationPath(Map pojoAnnotations, Map method) throws IOException {
+
+ String path = getPath(pojoAnnotations);
+ Map pathAnno = new HashMap<>();
+ if (pojoAnnotations.containsKey(this.javaxPath)) {
+ pathAnno = (Map) pojoAnnotations.get(this.javaxPath);
+ } else if (pojoAnnotations.containsKey(this.requestMapping)) {
+ pathAnno = (Map) pojoAnnotations.get(this.requestMapping);
+ }
+ if (pathAnno.containsKey("value")) {
+ String toAdd = (String) pathAnno.get("value");
+ if (toAdd.startsWith("/") && path.endsWith("/")) {
+ path += toAdd.substring(1);
+ }
+ }
+ return path;
+ }
+
+ /**
+ * Gets the path of a component
+ *
+ * @param pojoAnnotations the annotation map of the given pojo
+ * @return The communal path of a component
+ * @throws IOException If no application_properties file is found
+ */
+ public String getPath(Map pojoAnnotations) throws IOException {
+
+ String path = extractRootPath();
+ Map pathAnno = new HashMap<>();
+ if (pojoAnnotations.containsKey(this.javaxPath)) {
+ pathAnno = (Map) pojoAnnotations.get(this.javaxPath);
+ } else if (pojoAnnotations.containsKey(this.requestMapping)) {
+ pathAnno = (Map) pojoAnnotations.get(this.requestMapping);
+ }
+ if (pathAnno.containsKey("value")) {
+ String toAdd = (String) pathAnno.get("value");
+ if (toAdd.startsWith("/") && path.endsWith(":")) {
+ path += toAdd.substring(1);
+ }
+ }
+ return path;
+ }
+
+ /**
+ * Checks the class path for an application.properties file and extracts the port and path from it
+ *
+ * @return The root path of the application
+ * @throws IOException If no application.properties file could be found
+ */
+ private String extractRootPath() throws IOException {
+
+ Class> clazz = this.getClass();
+ String t = "";
+ StringBuilder sb = new StringBuilder("http://localhost:");
+ try (InputStream in = clazz.getClassLoader().getResourceAsStream("application.properties")) {
+ if (in != null) {
+ try (InputStreamReader reader = new InputStreamReader(in); BufferedReader br = new BufferedReader(reader)) {
+ while ((t = br.readLine()) != null) {
+ if (t.matches("server\\.port=(\\d{0,5})") || t.matches("server\\.context-path=([^\\s]*)")) {
+ sb.append(t.substring(t.indexOf('=') + 1));
+ }
+ }
+ return sb.toString();
+ }
+ } else {
+ return "";
+ }
+ }
+ }
+
+ /**
+ * Helper method to find a class's specific method
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName The name of the method to be found
+ * @return The method object of the method to be found, null if it wasn't found
+ */
+ private Method findMethod(Class> pojoClass, String methodName) {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+ for (Method m : pojoClass.getMethods()) {
+ if (m.getName().equals(methodName)) {
+ return m;
+ }
+ }
+ return null;
+ }
+}
diff --git a/cobigen-templates/templates-devon4j-tests/src/test/java/com/devonfw/cobigen/templates/devon4j/test/templates/TemplatesGenerationTest.java b/cobigen-templates/templates-devon4j-tests/src/test/java/com/devonfw/cobigen/templates/devon4j/test/templates/TemplatesGenerationTest.java
index 62734aa1fe..c5ef518ff1 100644
--- a/cobigen-templates/templates-devon4j-tests/src/test/java/com/devonfw/cobigen/templates/devon4j/test/templates/TemplatesGenerationTest.java
+++ b/cobigen-templates/templates-devon4j-tests/src/test/java/com/devonfw/cobigen/templates/devon4j/test/templates/TemplatesGenerationTest.java
@@ -5,6 +5,8 @@
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
import java.util.stream.Stream;
import org.apache.commons.io.FileUtils;
@@ -64,37 +66,40 @@ public static void setupDevTemplates() throws URISyntaxException, IOException {
FileUtils.copyDirectory(templatesProject.toFile(), templateSetsAdaptedFolder.toFile());
+ List devTemplateSets = new ArrayList<>();
try (Stream files = Files.list(templateSetsAdaptedFolder)) {
files.forEach(path -> {
- if (Files.isDirectory(path)) {
- Path resourcesFolder = path.resolve("src/main/resources");
- Path templatesFolder = path.resolve(ConfigurationConstants.TEMPLATE_RESOURCE_FOLDER);
- if (Files.exists(resourcesFolder) && !Files.exists(templatesFolder)) {
- try {
- Files.move(resourcesFolder, templatesFolder);
- } catch (IOException e) {
- e.printStackTrace();
- }
+ devTemplateSets.add(path);
+ });
+ }
+
+ for (Path path : devTemplateSets) {
+ if (Files.isDirectory(path)) {
+ Path resourcesFolder = path.resolve("src/main/resources");
+ Path templatesFolder = path.resolve(ConfigurationConstants.TEMPLATE_RESOURCE_FOLDER);
+ if (Files.exists(resourcesFolder) && !Files.exists(templatesFolder)) {
+ try {
+ Files.move(resourcesFolder, templatesFolder);
+ } catch (IOException e) {
+ throw new IOException("Error moving directory " + resourcesFolder, e);
}
}
- // Replace the pom.xml in the utils project. Needed so that the utils project in the temp directory is build
+ // Replace the pom.xml in the template sets. Needed so that the project in the temp directory is build
// properly
- if (path.getFileName().toString().equals("templates-devon4j-utils")) {
- if (Files.exists(path.resolve("pom.xml"))) {
- try {
- Files.delete(path.resolve("pom.xml"));
- } catch (IOException e) {
- e.printStackTrace();
- }
+ if (Files.exists(path.resolve("pom.xml"))) {
+ try {
+ Files.delete(path.resolve("pom.xml"));
+ } catch (IOException e) {
+ throw new IOException("Error deleting file " + path.resolve("pom.xml"), e);
}
try {
Files.copy(utilsPom, path.resolve("pom.xml"));
} catch (IOException e) {
- e.printStackTrace();
+ throw new IOException("Error copying file " + utilsPom, e);
}
}
- });
+ }
}
}
}
diff --git a/cobigen-templates/testdata-builder/pom.xml b/cobigen-templates/testdata-builder/pom.xml
index 4834e41433..a54f9980ee 100644
--- a/cobigen-templates/testdata-builder/pom.xml
+++ b/cobigen-templates/testdata-builder/pom.xml
@@ -10,4 +10,10 @@
${revision}
+
+
+ org.apache.commons
+ commons-lang3
+
+
\ No newline at end of file
diff --git a/cobigen-templates/testdata-builder/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java b/cobigen-templates/testdata-builder/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java
new file mode 100644
index 0000000000..2d4025071d
--- /dev/null
+++ b/cobigen-templates/testdata-builder/src/main/java/com/devonfw/cobigen/templates/devon4j/utils/JavaUtil.java
@@ -0,0 +1,464 @@
+package com.devonfw.cobigen.templates.devon4j.utils;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.commons.lang3.ClassUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Provides type operations, mainly checks and casts for Java Primitives, to be used in the templates
+ *
+ */
+public class JavaUtil {
+
+ /**
+ * Logger for this class
+ */
+ private static final Logger LOG = LoggerFactory.getLogger(JavaUtil.class);
+
+ /**
+ * The constructor.
+ */
+ public JavaUtil() {
+
+ // Empty for CobiGen to automatically instantiate it
+ }
+
+ /**
+ * Returns the Object version of a Java primitive or the input if the input isn't a java primitive
+ *
+ * @param simpleType String
+ * @return the corresponding object wrapper type simple name of the input if the input is the name of a primitive java
+ * type. The input itself if not. (e.g. "int" results in "Integer")
+ * @throws ClassNotFoundException should not occur.
+ */
+ public String boxJavaPrimitives(String simpleType) throws ClassNotFoundException {
+
+ if (equalsJavaPrimitive(simpleType)) {
+ return ClassUtils.primitiveToWrapper(ClassUtils.getClass(simpleType)).getSimpleName();
+ } else {
+ return simpleType;
+ }
+
+ }
+
+ /**
+ * Returns the simple name of the type of a field in the pojoClass. If the type is a java primitive the name of the
+ * wrapper class is returned
+ *
+ * @param pojoClass {@link Class} the class object of the pojo
+ * @param fieldName {@link String} the name of the field
+ * @return String. The simple name of the field's type. The simple name of the wrapper class in case of java
+ * primitives
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public String boxJavaPrimitives(Class> pojoClass, String fieldName) throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+
+ if (equalsJavaPrimitive(pojoClass, fieldName)) {
+ return ClassUtils.primitiveToWrapper(pojoClass.getDeclaredField(fieldName).getType()).getSimpleName();
+ } else {
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ throw new IllegalAccessError("Could not find field " + fieldName + " in class " + pojoClass);
+ } else {
+ return field.getType().getSimpleName();
+ }
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive
+ *
+ * @param simpleType the type to be checked
+ * @return true iff simpleType is a Java primitive
+ */
+ public boolean equalsJavaPrimitive(String simpleType) {
+
+ try {
+ return ClassUtils.getClass(simpleType).isPrimitive();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive or wrapper
+ *
+ * @param simpleType the type to be checked
+ * @return true iff simpleType is a Java primitive or wrapper
+ */
+ public boolean equalsJavaPrimitiveOrWrapper(String simpleType) {
+
+ try {
+ return ClassUtils.isPrimitiveOrWrapper(ClassUtils.getClass(simpleType));
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the type of the field in the pojo's class is a java primitive
+ *
+ * @param pojoClass the {@link Class} object of the pojo
+ * @param fieldName the name of the field to be checked
+ * @return true iff the field is a java primitive
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean equalsJavaPrimitive(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ return false;
+ }
+
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ return false;
+ } else {
+ return field.getType().isPrimitive();
+ }
+ }
+
+ /**
+ * Checks if the given type is a Java primitive or a Java primitive array
+ *
+ * @param simpleType the Type name to be checked
+ * @return true iff {@link #equalsJavaPrimitive(String)} is true or if simpleType is an array with a primitive
+ * component
+ */
+ public boolean equalsJavaPrimitiveIncludingArrays(String simpleType) {
+
+ Class> klasse;
+
+ try {
+ klasse = ClassUtils.getClass(simpleType).getComponentType();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), simpleType);
+ return false;
+ }
+ return equalsJavaPrimitive(simpleType) || (klasse != null && klasse.isPrimitive());
+ }
+
+ /**
+ * Checks if the given field in the pojo class is a java primitive or an array of java primitives
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldName the name of the field to be checked
+ * @return true iff {@link #equalsJavaPrimitive(Class, String)} is true or the field is an array of primitives
+ * @throws NoSuchFieldException indicating something awfully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean equalsJavaPrimitiveIncludingArrays(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ return equalsJavaPrimitive(pojoClass, fieldName) || (pojoClass.getDeclaredField(fieldName).getType().isArray()
+ && pojoClass.getDeclaredField(fieldName).getType().getComponentType().isPrimitive());
+ }
+
+ /**
+ * Returns a cast statement for a given (java primitive, variable name) pair or nothing if the type isn't a java
+ * primitive
+ *
+ * @param simpleType Java Type
+ * @param varName Variable name
+ * @return String either of the form '((Java Primitive Object Type)varName)' if simpleType is a primitive or the empty
+ * String otherwise
+ * @throws ClassNotFoundException should not occur
+ */
+ public String castJavaPrimitives(String simpleType, String varName) throws ClassNotFoundException {
+
+ if (equalsJavaPrimitive(simpleType)) {
+ return String.format("((%1$s)%2$s)", boxJavaPrimitives(simpleType), varName);
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * Returns a cast statement for a given (java primitive, variable name) pair or nothing if the type isn't a java
+ * primitive
+ *
+ * @param pojoClass the class object of the pojo
+ * @param fieldName the name of the field to be casted
+ * @return if fieldName points to a primitive field then a casted statement (e.g. for an int field:
+ * '((Integer)field)') or an empty String otherwise
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public String castJavaPrimitives(Class> pojoClass, String fieldName)
+ throws NoSuchFieldException, SecurityException {
+
+ if (equalsJavaPrimitive(pojoClass, fieldName)) {
+ return String.format("((%1$s)%2$s)", boxJavaPrimitives(pojoClass, fieldName), fieldName);
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * @param pojoClass {@link Class} the class object of the pojo
+ * @param fieldName {@link String} the name of the field
+ * @return true if the field is an instance of java.utils.Collections
+ * @throws NoSuchFieldException indicating something awefully wrong in the used model
+ * @throws SecurityException if the field cannot be accessed.
+ */
+ public boolean isCollection(Class> pojoClass, String fieldName) throws NoSuchFieldException, SecurityException {
+
+ if (pojoClass == null) {
+ return false;
+ }
+
+ Field field = pojoClass.getDeclaredField(fieldName);
+ if (field == null) {
+ field = pojoClass.getField(fieldName);
+ }
+ if (field == null) {
+ return false;
+ } else {
+ return Collection.class.isAssignableFrom(field.getType());
+ }
+
+ }
+
+ /**
+ * Returns the Ext Type to a given java type
+ *
+ * @param simpleType any java type's simple name
+ * @return corresponding Ext type
+ */
+ public String getExtType(String simpleType) {
+
+ switch (simpleType) {
+ case "short":
+ case "Short":
+ case "int":
+ case "Integer":
+ case "long":
+ case "Long":
+ return "Integer";
+ case "float":
+ case "Float":
+ case "double":
+ case "Double":
+ return "Number";
+ case "boolean":
+ case "Boolean":
+ return "Boolean";
+ case "char":
+ case "Character":
+ case "String":
+ return "String";
+ case "Date":
+ return "Date";
+ default:
+ return "Field";
+ }
+ }
+
+ /**
+ * returns the Angular5 type associated with a Java primitive
+ *
+ * @param simpleType :{@link String} the type to be parsed
+ * @return the corresponding Angular type or 'any' otherwise
+ */
+ public String getAngularType(String simpleType) {
+
+ switch (simpleType) {
+ case "boolean":
+ return "boolean";
+ case "Boolean":
+ return "boolean";
+ case "short":
+ return "number";
+ case "Short":
+ return "number";
+ case "int":
+ return "number";
+ case "Integer":
+ return "number";
+ case "long":
+ return "number";
+ case "Long":
+ return "number";
+ case "float":
+ return "number";
+ case "Float":
+ return "number";
+ case "double":
+ return "number";
+ case "Double":
+ return "number";
+ case "char":
+ return "string";
+ case "Character":
+ return "string";
+ case "String":
+ return "string";
+ case "byte":
+ return "number";
+ default:
+ return "any";
+ }
+ }
+
+ /**
+ * returns the class name of the return type of a specific method.
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName {@link String} the name of the method
+ * @return the class name of the return type of the specified method
+ * @throws SecurityException If no method of the given name can be found
+ * @throws NoSuchMethodException If no method of the given name can be found
+ */
+ public String getReturnType(Class> pojoClass, String methodName) throws NoSuchMethodException, SecurityException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+ String s = "-";
+ Method method = findMethod(pojoClass, methodName);
+ if (method != null && !method.getReturnType().equals(Void.TYPE)) {
+ s = method.getReturnType().toString();
+ s = s.substring(s.lastIndexOf('.') + 1, s.length());
+ }
+ return s;
+ }
+
+ /**
+ *
+ * This methods returns the return type of the method in the given pojoClass which are annotated with the parameter
+ * annotatedClass
+ *
+ * @param pojoClass - The class in which to find if it has methods with annotatedClass
+ * @param annotatedClassName - The annotation which needs to be found
+ * @return Return type of the method annotated with the given annotation, else "null"
+ * @throws ClassNotFoundException if the annotated class name could not be found in the class path
+ */
+ @SuppressWarnings("unchecked")
+ public String getReturnTypeOfMethodAnnotatedWith(Class> pojoClass, String annotatedClassName)
+ throws ClassNotFoundException {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+
+ Method[] methods = pojoClass.getDeclaredMethods();
+ for (Method method : methods) {
+ if (!method.getName().startsWith("get")) {
+ continue;
+ }
+ for (Annotation a : method.getAnnotations()) {
+ // better if (method.isAnnotationPresent(classObj)) {, but postponed as of different class
+ // loaders of a.getClass() and pojoClass.getClass()
+ if (a.getClass().getCanonicalName().equals(annotatedClassName)) {
+ return method.getReturnType().getSimpleName();
+ }
+ }
+ }
+ return "null";
+ }
+
+ /**
+ * returns the HTTP request type corresponding to an annotation type
+ *
+ * @param annotations The annotation to get the type name of
+ * @return the HTTP request type name of the selected annotation
+ */
+ public String getRequestType(Map annotations) {
+
+ if (annotations.containsKey("javax_ws_rs_GET")) {
+ return "GET";
+ } else if (annotations.containsKey("javax_ws_rs_PUT")) {
+ return "PUT";
+ } else if (annotations.containsKey("javax_ws_rs_POST")) {
+ return "POST";
+ } else if (annotations.containsKey("javax_ws_rs_DELETE")) {
+ return "DELETE";
+ } else if (annotations.containsKey("javax_ws_rs_PATCH")) {
+ return "PATCH";
+ } else {
+ return "-";
+ }
+ }
+
+ /**
+ * Helper method to find a class's specific method
+ *
+ * @param pojoClass {@link Class}<?> the class object of the pojo
+ * @param methodName The name of the method to be found
+ * @return The method object of the method to be found, null if it wasn't found
+ */
+ private Method findMethod(Class> pojoClass, String methodName) {
+
+ if (pojoClass == null) {
+ throw new IllegalAccessError(
+ "Class object is null. Cannot generate template as it might obviously depend on reflection.");
+ }
+ for (Method m : pojoClass.getMethods()) {
+ if (m.getName().equals(methodName)) {
+ return m;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Checks whether the class given by the full qualified name is an enum
+ *
+ * @param className full qualified class name
+ * @return true
if the class is an enum, false
otherwise
+ */
+ public boolean isEnum(String className) {
+
+ try {
+ return ClassUtils.getClass(className).isEnum();
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), className);
+ return false;
+ }
+ }
+
+ /**
+ * Returns the first enum value of an enum class
+ *
+ * @param className full qualified class name
+ * @return the first enum value name found in order
+ */
+ public String getFirstEnumValue(String className) {
+
+ try {
+ Class> enumClass = ClassUtils.getClass(className);
+ Field[] declaredFields = enumClass.getDeclaredFields();
+ if (declaredFields.length > 0) {
+ return declaredFields[0].getName();
+ } else {
+ return null;
+ }
+ } catch (ClassNotFoundException e) {
+ LOG.warn("{}: Could not find {}", e.getMessage(), className);
+ return null;
+ }
+ }
+}
diff --git a/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/util/MavenUtil.java b/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/util/MavenUtil.java
index 0b221f9a63..a50d684117 100644
--- a/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/util/MavenUtil.java
+++ b/cobigen/cobigen-core-api/src/main/java/com/devonfw/cobigen/api/util/MavenUtil.java
@@ -115,6 +115,9 @@ public static Path createCachedPomFromJar(Path pomFile, Path outputPath) {
Path cachedPomXml = outputPath.resolve("cached-pom.xml");
try {
+ if (Files.exists(cachedPomXml)) {
+ Files.delete(cachedPomXml);
+ }
Files.copy(pomFile, cachedPomXml);
} catch (IOException e) {
throw new CobiGenRuntimeException("Unable to extract " + pomFile.toUri() + " from JAR to " + cachedPomXml, e);
diff --git a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/config/ConfigurationHolder.java b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/config/ConfigurationHolder.java
index 619076d0a1..ebf6c2cb54 100644
--- a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/config/ConfigurationHolder.java
+++ b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/config/ConfigurationHolder.java
@@ -1,14 +1,12 @@
package com.devonfw.cobigen.impl.config;
-import java.io.File;
-import java.io.FilenameFilter;
+import java.io.IOException;
import java.net.URI;
-import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
import com.devonfw.cobigen.api.constants.ConfigurationConstants;
import com.devonfw.cobigen.api.exception.InvalidConfigurationException;
@@ -34,22 +32,6 @@ public class ConfigurationHolder {
/** The OS filesystem path of the configuration */
private URI configurationLocation;
- public static String UTILS_REGEX_NAME = "templates-devon4j-utils.*";
-
- /**
- * Filters the files on a directory so that we can check whether the templates jar are already downloaded
- */
- static FilenameFilter utilsFilter = new FilenameFilter() {
-
- @Override
- public boolean accept(File dir, String name) {
-
- Pattern p = Pattern.compile(UTILS_REGEX_NAME);
- Matcher m = p.matcher(name);
- return m.find();
- }
- };
-
/**
* Creates a new {@link ConfigurationHolder} which serves as a cache for CobiGen's external configuration.
*
@@ -97,7 +79,7 @@ public Path getConfigurationPath() {
*/
public TemplatesConfiguration readTemplatesConfiguration(Trigger trigger) {
- Path configRoot = readContextConfiguration().getConfigRootforTrigger(trigger.getId());
+ Path configRoot = readContextConfiguration().getConfigLocationforTrigger(trigger.getId(), true);
Path templateFolder = Paths.get(trigger.getTemplateFolder());
if (!this.templatesConfigurations.containsKey(trigger.getId())) {
TemplatesConfiguration config = new TemplatesConfiguration(configRoot, trigger, this);
@@ -139,29 +121,22 @@ public boolean isTemplateSetConfiguration() {
* Search for the location of the Java utils
*
* @return the {@link Path} of the location of the util classes or null if no location was found
+ * @throws IOException
*/
- public Path getUtilsLocation() {
+ public List getUtilsLocation() {
+ List utilsLocationPaths = new ArrayList<>();
if (isTemplateSetConfiguration()) {
- Path adaptedFolder = this.configurationPath.resolve(ConfigurationConstants.ADAPTED_FOLDER);
- Path downloadedFolder = this.configurationPath.resolve(ConfigurationConstants.DOWNLOADED_FOLDER);
-
- String[] utils;
- if (Files.exists(adaptedFolder)) {
- utils = adaptedFolder.toFile().list(utilsFilter);
- if (utils.length > 0) {
- return adaptedFolder.resolve(utils[0]);
- }
- }
+ List triggers = readContextConfiguration().getTriggers();
- if (Files.exists(downloadedFolder)) {
- utils = downloadedFolder.toFile().list(utilsFilter);
- if (utils.length > 0) {
- return downloadedFolder.resolve(utils[0]);
- }
+ for (Trigger trigger : triggers) {
+ Path configLocation = readContextConfiguration().getConfigLocationforTrigger(trigger.getId(), false);
+ utilsLocationPaths.add(configLocation);
}
- return null;
+ } else {
+ utilsLocationPaths.add(Paths.get(this.configurationLocation));
}
- return Paths.get(this.configurationLocation);
+
+ return utilsLocationPaths;
}
}
diff --git a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/config/ContextConfiguration.java b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/config/ContextConfiguration.java
index c5c7aa4585..fe34c1c7f0 100644
--- a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/config/ContextConfiguration.java
+++ b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/config/ContextConfiguration.java
@@ -11,6 +11,7 @@
import com.devonfw.cobigen.impl.config.reader.AbstractContextConfigurationReader;
import com.devonfw.cobigen.impl.config.reader.ContextConfigurationReaderFactory;
import com.devonfw.cobigen.impl.config.reader.ContextConfigurationSetReader;
+import com.devonfw.cobigen.impl.util.FileSystemUtil;
/**
* The {@link ContextConfiguration} is a configuration data wrapper for all information about templates and the target
@@ -105,15 +106,21 @@ public Path getConfigurationPath() {
}
/**
- * @param triggerId the trigger id to get the config root directory for
- * @return the {@link Path} of the config root directory of the trigger
+ * @param triggerId the trigger id to get the config location for
+ * @param fileSystemDependentPath if true and the configuration is a jar file, the file system dependent path is
+ * returned
+ * @return the {@link Path} of the config location of the trigger
*/
- public Path getConfigRootforTrigger(String triggerId) {
+ public Path getConfigLocationforTrigger(String triggerId, boolean fileSystemDependentPath) {
if (this.contextConfigurationReader instanceof ContextConfigurationSetReader) {
- return ((ContextConfigurationSetReader) this.contextConfigurationReader).getConfigRootForTrigger(triggerId);
+ Path configLocation = ((ContextConfigurationSetReader) this.contextConfigurationReader)
+ .getConfigLocationForTrigger(triggerId);
+ if (fileSystemDependentPath && FileSystemUtil.isZipFile(configLocation.toUri())) {
+ configLocation = FileSystemUtil.createFileSystemDependentPath(configLocation.toUri());
+ }
+ return configLocation;
}
return this.contextConfigurationReader.getContextRoot();
}
-
}
diff --git a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/config/reader/ContextConfigurationSetReader.java b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/config/reader/ContextConfigurationSetReader.java
index 9c16535e32..7704c77534 100644
--- a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/config/reader/ContextConfigurationSetReader.java
+++ b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/config/reader/ContextConfigurationSetReader.java
@@ -21,11 +21,11 @@
/** The {@link ContextConfigurationSetReader} reads the context xml */
public class ContextConfigurationSetReader extends AbstractContextConfigurationReader {
- /** Map with the paths of the config roots for a context.xml file */
- private Map configRoots = new HashMap<>();
+ /** Map with the paths of the config locations for a context.xml file */
+ private Map configLocations = new HashMap<>();
- /** Map with the paths of the config roots for a trigger */
- private Map triggerConfigRoots = new HashMap<>();
+ /** Map with the paths of the config location for a trigger */
+ private Map triggerConfigLocations = new HashMap<>();
/**
* The constructor.
@@ -111,7 +111,7 @@ private List loadContextFilesDownloaded(Path configRoot) {
Path contextFilePath = configurationPath.resolve(ConfigurationConstants.TEMPLATE_RESOURCE_FOLDER)
.resolve(ConfigurationConstants.CONTEXT_CONFIG_FILENAME);
- addConfigRoot(contextFilePath, configurationPath, contextPaths);
+ addConfigRoot(contextFilePath, jarPath, contextPaths);
}
}
@@ -123,28 +123,22 @@ public Map loadTriggers() {
Map triggers = Maps.newHashMap();
for (Path contextFile : this.contextConfigurations.keySet()) {
- Path configRoot = this.configRoots.get(contextFile);
ContextConfiguration contextConfiguration = this.contextConfigurations.get(contextFile);
- boolean isJarConfig = (configRoot.getParent() == null);
+ Path configLocation = this.configLocations.get(contextFile);
+ boolean isJarFile = FileSystemUtil.isZipFile(configLocation.toUri());
List triggerList = contextConfiguration.getTrigger();
if (!triggerList.isEmpty()) {
// context configuration in template sets consists of only one trigger
com.devonfw.cobigen.impl.config.entity.io.Trigger trigger = triggerList.get(0);
- String templateFolder;
- if (isJarConfig) {
- templateFolder = contextFile.getParent().toString();
- } else {
- templateFolder = configRoot.getFileName().resolve(ConfigurationConstants.TEMPLATE_RESOURCE_FOLDER).toString();
- configRoot = configRoot.getParent();
- }
-
- if (!this.triggerConfigRoots.containsKey(trigger.getId()) || !isJarConfig) {
+ if (!this.triggerConfigLocations.containsKey(trigger.getId()) || !isJarFile) {
// prefer the adapted templates
- this.triggerConfigRoots.put(trigger.getId(), configRoot);
- triggers.put(trigger.getId(), new Trigger(trigger.getId(), trigger.getType(), templateFolder,
- Charset.forName(trigger.getInputCharset()), loadMatchers(trigger), loadContainerMatchers(trigger)));
+ this.triggerConfigLocations.put(trigger.getId(), configLocation);
+
+ triggers.put(trigger.getId(),
+ new Trigger(trigger.getId(), trigger.getType(), ConfigurationConstants.TEMPLATE_RESOURCE_FOLDER,
+ Charset.forName(trigger.getInputCharset()), loadMatchers(trigger), loadContainerMatchers(trigger)));
}
}
}
@@ -152,14 +146,14 @@ public Map loadTriggers() {
}
/**
- * Get the configuration root directory for a given trigger
+ * Get the configuration location for a given trigger. Either a jar file or a folder
*
* @param triggerId the trigger id to search the config root for
- * @return the {@link Path} of the config root for a trigger
+ * @return the {@link Path} of the config location for a trigger
*/
- public Path getConfigRootForTrigger(String triggerId) {
+ public Path getConfigLocationForTrigger(String triggerId) {
- return this.triggerConfigRoots.get(triggerId);
+ return this.triggerConfigLocations.get(triggerId);
}
/**
@@ -174,7 +168,7 @@ private void addConfigRoot(Path contextFilePath, Path configRootPath, List
if (Files.exists(contextFilePath)) {
contextPaths.add(contextFilePath);
- this.configRoots.put(contextFilePath, configRootPath);
+ this.configLocations.put(contextFilePath, configRootPath);
}
}
}
diff --git a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/generator/GenerationProcessorImpl.java b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/generator/GenerationProcessorImpl.java
index 22e550f59b..4a2029fb50 100644
--- a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/generator/GenerationProcessorImpl.java
+++ b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/generator/GenerationProcessorImpl.java
@@ -11,6 +11,7 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Formatter;
import java.util.List;
@@ -262,43 +263,48 @@ private ClassLoader prependTemplatesClassloader(ClassLoader inputProjectClassLoa
ClassLoader combinedClassLoader = inputProjectClassLoader != null ? inputProjectClassLoader
: Thread.currentThread().getContextClassLoader();
- if (configLocation != null && this.configurationHolder.getUtilsLocation() != null) {
-
- Path utilsLocation = this.configurationHolder.getUtilsLocation();
- Path pomFile;
- if (FileSystemUtil.isZipFile(utilsLocation.toUri())) {
- Path utilsPath = FileSystemUtil.createFileSystemDependentPath(utilsLocation.toUri());
- pomFile = utilsPath.resolve("pom.xml");
- } else {
- pomFile = utilsLocation.resolve("pom.xml");
- }
-
+ if (configLocation != null && !this.configurationHolder.getUtilsLocation().isEmpty()) {
+ List utilsLocations = this.configurationHolder.getUtilsLocation();
Path cpCacheFile = null;
try {
- if (Files.exists(pomFile)) {
- LOG.debug("Found templates to be configured by maven.");
+ List urlList = new ArrayList<>();
+ for (Path utilsLocation : utilsLocations) {
- String pomFileHash = MavenUtil.generatePomFileHash(pomFile);
-
- if (this.configurationHolder.isJarConfig()) {
- cpCacheFile = configLocation
- .resolveSibling(String.format(MavenConstants.CLASSPATH_CACHE_FILE, pomFileHash));
+ Path pomFile;
+ if (FileSystemUtil.isZipFile(utilsLocation.toUri())) {
+ Path utilsPath = FileSystemUtil.createFileSystemDependentPath(utilsLocation.toUri());
+ pomFile = utilsPath.resolve("pom.xml");
} else {
- cpCacheFile = configLocation.resolve(String.format(MavenConstants.CLASSPATH_CACHE_FILE, pomFileHash));
+ pomFile = utilsLocation.resolve("pom.xml");
}
- combinedClassLoader = MavenUtil.addURLsFromCachedClassPathsFile(cpCacheFile, pomFile, combinedClassLoader);
- }
+ if (Files.exists(pomFile)) {
+ String pomFileHash = MavenUtil.generatePomFileHash(pomFile);
- // prepend jar/compiled resources as well
- URL[] urls;
- if (Files.isDirectory(utilsLocation) && Files.exists(pomFile)) {
- compileTemplateUtils(utilsLocation);
- urls = new URL[] { utilsLocation.resolve("target").resolve("classes").toUri().toURL() };
- } else {
- urls = new URL[] { utilsLocation.toUri().toURL() };
+ if (!this.configurationHolder.isTemplateSetConfiguration()) {
+ if (this.configurationHolder.isJarConfig()) {
+ cpCacheFile = configLocation
+ .resolveSibling(String.format(MavenConstants.CLASSPATH_CACHE_FILE, pomFileHash));
+ } else {
+ cpCacheFile = configLocation.resolve(String.format(MavenConstants.CLASSPATH_CACHE_FILE, pomFileHash));
+ }
+ } else {
+ cpCacheFile = configLocation.resolve(String.format(MavenConstants.CLASSPATH_CACHE_FILE, pomFileHash));
+ }
+
+ combinedClassLoader = MavenUtil.addURLsFromCachedClassPathsFile(cpCacheFile, pomFile, combinedClassLoader);
+ }
+
+ if (Files.isDirectory(utilsLocation) && Files.exists(pomFile)) {
+ compileTemplateUtils(utilsLocation);
+ urlList.add(utilsLocation.resolve("target").resolve("classes").toUri().toURL());
+ } else {
+ urlList.add(utilsLocation.toUri().toURL());
+ }
}
+ // prepend jar/compiled resources as well
+ URL[] urls = urlList.toArray(new URL[urlList.size()]);
combinedClassLoader = new URLClassLoader(urls, combinedClassLoader);
return combinedClassLoader;
} catch (MalformedURLException e) {
@@ -422,7 +428,7 @@ private void generate(TemplateTo template, TriggerInterpreter triggerInterpreter
TextTemplateEngine templateEngine = TemplateEngineRegistry.getEngine(templateEngineName);
templateEngine.setTemplateFolder(this.configurationHolder.readContextConfiguration()
- .getConfigRootforTrigger(trigger.getId()).resolve(trigger.getTemplateFolder()));
+ .getConfigLocationforTrigger(trigger.getId(), true).resolve(trigger.getTemplateFolder()));
Template templateEty = tConfig.getTemplate(template.getId());
if (templateEty == null) {
diff --git a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/util/ConfigurationClassLoaderUtil.java b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/util/ConfigurationClassLoaderUtil.java
index 408f318251..1d3ffa87ef 100644
--- a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/util/ConfigurationClassLoaderUtil.java
+++ b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/util/ConfigurationClassLoaderUtil.java
@@ -118,14 +118,16 @@ public static List> resolveUtilClasses(ConfigurationHolder configuratio
List> result = new LinkedList<>();
List classLoaderUrls = new ArrayList<>(); // stores ClassLoader URLs
- Path utilsLocation = configurationHolder.getUtilsLocation();
- if (FileSystemUtil.isZipFile(utilsLocation.toUri())) {
- result = resolveFromJar(classLoader, configurationHolder);
- } else {
- ClassLoader inputClassLoader = null;
- classLoaderUrls = addFoldersToClassLoaderUrls(utilsLocation);
- inputClassLoader = getUrlClassLoader(classLoaderUrls.toArray(new URL[] {}), classLoader);
- result = resolveFromFolder(utilsLocation, inputClassLoader);
+ List utilsLocations = configurationHolder.getUtilsLocation();
+ for (Path utilsLocation : utilsLocations) {
+ if (FileSystemUtil.isZipFile(utilsLocation.toUri())) {
+ result.addAll(resolveFromJar(classLoader, utilsLocation));
+ } else {
+ ClassLoader inputClassLoader = null;
+ classLoaderUrls = addFoldersToClassLoaderUrls(utilsLocation);
+ inputClassLoader = getUrlClassLoader(classLoaderUrls.toArray(new URL[] {}), classLoader);
+ result.addAll(resolveFromFolder(utilsLocation, inputClassLoader));
+ }
}
return result;
@@ -183,15 +185,15 @@ private static List> resolveFromFolder(Path templateRoot, ClassLoader i
* @param configurationHolder configuration holder
* @return List of classes to load utilities from
*/
- private static List> resolveFromJar(ClassLoader inputClassLoader, ConfigurationHolder configurationHolder) {
+ private static List> resolveFromJar(ClassLoader inputClassLoader, Path utilLocation) {
- LOG.debug("Processing configuration archive {}", configurationHolder.getUtilsLocation());
+ LOG.debug("Processing configuration archive {}", utilLocation);
LOG.info("Searching for classes in configuration archive...");
List> result = new ArrayList<>();
List foundClasses = new LinkedList<>();
try {
- foundClasses = walkJarFile(configurationHolder);
+ foundClasses = walkJarFile(utilLocation);
} catch (IOException e) {
LOG.error("Could not read templates jar file", e);
}
@@ -250,14 +252,14 @@ public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOExce
* @return List of file paths containing class files
* @throws IOException if file could not be visited
*/
- private static List walkJarFile(ConfigurationHolder configurationHolder) throws IOException {
+ private static List walkJarFile(Path utilLocation) throws IOException {
List foundClasses = new LinkedList<>();
// walk the jar file
- LOG.debug("Searching for classes in {}", configurationHolder.getUtilsLocation());
- Path configurationPath = configurationHolder.getUtilsLocation();
- if (FileSystemUtil.isZipFile(configurationPath.toUri())) {
- configurationPath = FileSystemUtil.createFileSystemDependentPath(configurationHolder.getUtilsLocation().toUri());
+ LOG.debug("Searching for classes in {}", utilLocation);
+ Path configurationPath = utilLocation;
+ if (FileSystemUtil.isZipFile(utilLocation.toUri())) {
+ configurationPath = FileSystemUtil.createFileSystemDependentPath(utilLocation.toUri());
}
Files.walkFileTree(configurationPath, new SimpleFileVisitor() {
diff --git a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/util/ExtractTemplatesUtil.java b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/util/ExtractTemplatesUtil.java
index bf286d3557..7b3046318c 100644
--- a/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/util/ExtractTemplatesUtil.java
+++ b/cobigen/cobigen-core/src/main/java/com/devonfw/cobigen/impl/util/ExtractTemplatesUtil.java
@@ -18,6 +18,7 @@
import java.util.List;
import java.util.Objects;
+import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -166,10 +167,7 @@ private static void processJars(Path destinationPath) throws IOException {
extractArchive(templateSetJar, destination);
if (Files.exists(destination.resolve("com"))) {
- // move com folder to src/main/java/com. Needed for the utils project
- Files.createDirectories(destination.resolve("src/main/java"));
- Files.move(destination.resolve("com"), destination.resolve("src/main/java/com"),
- StandardCopyOption.REPLACE_EXISTING);
+ FileUtils.deleteDirectory(destination.resolve("com").toFile());
}
}
} else {
diff --git a/pom.xml b/pom.xml
index 966bc9d229..d3f74992d9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -127,7 +127,7 @@
com.fasterxml.jackson.core
jackson-databind
- 2.10.0
+ 2.13.2.2
com.google.code.gson