Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide Maven plugin for generating TypeScript DTO objects based on Java DTO #2490

Merged
merged 1 commit into from
Sep 22, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions core/che-core-typescript-dto-maven-plugin/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--

Copyright (c) 2012-2016 Codenvy, S.A.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html

Contributors:
Codenvy, S.A. - initial API and implementation

-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>che-core-parent</artifactId>
<groupId>org.eclipse.che.core</groupId>
<version>5.0.0-M2-SNAPSHOT</version>
</parent>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-typescript-dto-maven-plugin</artifactId>
<packaging>maven-plugin</packaging>
<name>Che Core :: API :: TypeScript DTO maven plugin</name>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>org.antlr</groupId>
<artifactId>ST4</artifactId>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-dto</artifactId>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-model</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.sisu</groupId>
<artifactId>org.eclipse.sisu.plexus</artifactId>
<scope>provided</scope>
<exclusions>
<exclusion>
<artifactId>jsr250-api</artifactId>
<groupId>javax.annotation</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-compat</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-testing</groupId>
<artifactId>maven-plugin-testing-harness</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-utils</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<executions>
<execution>
<id>mojo-descriptor</id>
<goals>
<goal>descriptor</goal>
</goals>
</execution>
</executions>
<configuration>
<skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.plugin.typescript.dto;

import org.eclipse.che.dto.shared.DelegateTo;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

/**
* Helper class
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Provide more detailed javadoc for this helper class.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hum ok I will provide a new PR then as it has been merged

*
* @author Florent Benoit
*/
public class DTOHelper {

/**
* Utility class.
*/
private DTOHelper() {

}

/**
* Check is specified method is DTO getter.
*/
public static boolean isDtoGetter(Method method) {
if (method.isAnnotationPresent(DelegateTo.class)) {
return false;
}

if (method.getParameterTypes().length > 0) {
return false;
}

String methodName = method.getName();

return methodName.startsWith("get") ||
(methodName.startsWith("is") && ((method.getReturnType() == Boolean.class || method.getReturnType() == boolean.class)));

}


/**
* Check is specified method is DTO setter.
*/
public static boolean isDtoSetter(Method method) {
if (method.isAnnotationPresent(DelegateTo.class)) {
return false;
}
String methodName = method.getName();
return methodName.startsWith("set") && method.getParameterTypes().length == 1;
}

/**
* Check is specified method is DTO with.
*/
public static boolean isDtoWith(Method method) {
if (method.isAnnotationPresent(DelegateTo.class)) {
return false;
}
String methodName = method.getName();
return methodName.startsWith("with") && method.getParameterTypes().length == 1;
}

/**
* Compute field name from the stringified string type
*/
public static String getFieldName(String type) {
char[] c = type.toCharArray();
c[0] = Character.toLowerCase(c[0]);
return new String(c);
}

/**
* Extract field name from the getter method
*/
public static String getGetterFieldName(Method method) {
String methodName = method.getName();
if (methodName.startsWith("get")) {
return getFieldName(methodName.substring(3));
} else if (methodName.startsWith("is")) {
return getFieldName(methodName.substring(2));
}
throw new IllegalArgumentException("Invalid getter method" + method.getName());
}

/**
* Extract field name from the setter method
*/
public static String getSetterFieldName(Method method) {
String methodName = method.getName();
if (methodName.startsWith("set")) {
return getFieldName(methodName.substring(3));
}
throw new IllegalArgumentException("Invalid setter method" + method.getName());
}

/**
* Extract field name from the with method
*/
public static String getWithFieldName(Method method) {
String methodName = method.getName();
if (methodName.startsWith("with")) {
return getFieldName(methodName.substring(4));
}
throw new IllegalArgumentException("Invalid with method" + method.getName());
}

/**
* Convert Java type to TypeScript type
*/
public static String convertType(Type type) {
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType)type;
Type rawType = parameterizedType.getRawType();
return convertParametrizedType(type, parameterizedType, rawType);
} else if (String.class.equals(type) || (type instanceof Class && ((Class)type).isEnum())) {
// Maybe find a better enum type for typescript
return "string";
} else if (Integer.class.equals(type) || Integer.TYPE.equals(type) || Long.class.equals(type) || Long.TYPE.equals(type)) {
return "number";
} else if (Boolean.class.equals(type)) {
return "boolean";
}

return type.getTypeName();
}

/**
* Handle convert of a parametrized Java type to TypeScript type
*/
public static String convertParametrizedType(Type type, ParameterizedType parameterizedType, Type rawType) {

if (List.class.equals(rawType)) {
return "Array<" + convertType(parameterizedType.getActualTypeArguments()[0]) + ">";
} else if (Map.class.equals(rawType)) {
return "Map<" + convertType(parameterizedType.getActualTypeArguments()[0]) + "," +
convertType(parameterizedType.getActualTypeArguments()[1]) + ">";
} else {
throw new IllegalArgumentException("Invalid type" + type);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.plugin.typescript.dto;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectHelper;

import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;

/**
* Mojo for generating TypeScript DTO interface + implementation for handling JSON data.
* @author Florent Benoit
*/
@Mojo(name = "build",
defaultPhase = LifecyclePhase.PACKAGE,
requiresProject = true,
requiresDependencyCollection = ResolutionScope.RUNTIME)
public class TypeScriptDTOGeneratorMojo extends AbstractMojo {

/**
* Project providing artifact id, version and dependencies.
*/
@Parameter(defaultValue = "${project}", readonly = true)
private MavenProject project;

/**
* build directory used to write the intermediate bom file.
*/
@Parameter(defaultValue = "${project.build.directory}")
private File targetDirectory;

@Component
private MavenProjectHelper projectHelper;

/**
* Path to the generated typescript file
*/
private File typescriptFile;

/**
* Use of classpath instead of classloader
*/
private boolean useClassPath;

@Override
public void execute() throws MojoExecutionException, MojoFailureException {

getLog().info("Generating TypeScript DTO");

TypeScriptDtoGenerator typeScriptDtoGenerator = new TypeScriptDtoGenerator();

typeScriptDtoGenerator.setUseClassPath(useClassPath);

// define output path for the file to write with typescript definition
String output = typeScriptDtoGenerator.execute();

this.typescriptFile = new File(targetDirectory, project.getArtifactId() + ".ts");
File parentDir = this.typescriptFile.getParentFile();
if (!parentDir.exists() && !parentDir.mkdirs()) {
throw new MojoExecutionException("Unable to create a directory for writing DTO typescript file '" + parentDir + "'.");
}

try (Writer fileWriter = Files.newBufferedWriter(this.typescriptFile.toPath(), StandardCharsets.UTF_8)) {
fileWriter.write(output);
} catch (IOException e) {
throw new MojoExecutionException("Cannot write DTO typescript file");
}

// attach this typescript file as maven artifact
projectHelper.attachArtifact(project, "ts", typescriptFile);
}

/**
* Gets the TypeScript generated file
* @return the generated file TypeScript link
*/
public File getTypescriptFile() {
return typescriptFile;
}

/**
* Allow to configure generator to use classpath instead of classloader
* @param useClassPath true if want to use classpath loading
*/
public void setUseClassPath(boolean useClassPath) {
this.useClassPath = useClassPath;
}


}
Loading