Java tutorial
/** * Copyright 2010-2013 Nokia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.googlecode.jsonschema2pojo.ant; import static org.apache.commons.lang.StringUtils.*; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Task; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Reference; import com.googlecode.jsonschema2pojo.AnnotationStyle; import com.googlecode.jsonschema2pojo.Annotator; import com.googlecode.jsonschema2pojo.GenerationConfig; import com.googlecode.jsonschema2pojo.NoopAnnotator; import com.googlecode.jsonschema2pojo.SourceType; import com.googlecode.jsonschema2pojo.cli.Jsonschema2Pojo; /** * When invoked, this task reads one or more <a * href="http://json-schema.org/">JSON Schema</a> documents and generates DTO * style Java classes for data binding. * <p> * See <a href= * 'http://jsonschema2pojo.googlecode.com'>jsonschema2pojo.googlecode.com</a>. * * @see <a href="http://ant.apache.org/manual/develop.html">Writing Your Own * Task</a> */ public class Jsonschema2PojoTask extends Task implements GenerationConfig { private boolean generateBuilders; private boolean usePrimitives; private File source; private File targetDirectory; private String targetPackage; private boolean skip; private char[] propertyWordDelimiters = new char[] {}; private boolean useLongIntegers; private boolean includeHashcodeAndEquals = true; private boolean includeToString = true; private AnnotationStyle annotationStyle = AnnotationStyle.JACKSON; private Class<? extends Annotator> customAnnotator = NoopAnnotator.class; private boolean includeJsr303Annotations = false; private SourceType sourceType = SourceType.JSONSCHEMA; private Path classpath; private boolean removeOldOutput; /** * Execute this task (it's expected that all relevant setters will have been * called by Ant to provide task configuration <em>before</em> this method * is called). * * @throws BuildException * if this task cannot be completed due to some error reading * schemas, generating types or writing output .java files. */ @Override public void execute() throws BuildException { if (skip) { return; } if (source == null) { log("source attribute is required but was not set"); return; } if (!source.exists()) { log(source.getAbsolutePath() + " cannot be found"); return; } if (targetDirectory == null) { log("targetDirectory attribute is required but was not set"); return; } ClassLoader extendedClassloader = buildExtendedClassloader(); Thread.currentThread().setContextClassLoader(extendedClassloader); try { Jsonschema2Pojo.generate(this); } catch (IOException e) { throw new BuildException("Error generating classes from JSON Schema file(s) " + source.getPath(), e); } } /** * Build a classloader using the additional elements specified in * <code>classpath</code> and <code>classpathRef</code>. * * @return a new classloader that includes the extra path elements found in * the <code>classpath</code> and <code>classpathRef</code> config * values */ private ClassLoader buildExtendedClassloader() { final List<URL> classpathUrls = new ArrayList<URL>(); for (String pathElement : getClasspath().list()) { try { classpathUrls.add(new File(pathElement).toURI().toURL()); } catch (MalformedURLException e) { throw new BuildException( "Unable to use classpath entry as it could not be understood as a valid URL: " + pathElement, e); } } final ClassLoader parentClassloader = Thread.currentThread().getContextClassLoader(); return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() { @Override public ClassLoader run() { return new URLClassLoader(classpathUrls.toArray(new URL[classpathUrls.size()]), parentClassloader); } }); } /** * Sets the 'generateBuilders' property of this class. * * @param generateBuilders * Whether to generate builder-style methods of the form * <code>withXxx(value)</code> (that return <code>this</code>), * alongside the standard, void-return setters. * <p> * Default: <code>false</code>. */ public void setGenerateBuilders(boolean generateBuilders) { this.generateBuilders = generateBuilders; } /** * Sets the 'usePrimitives' property of this class. * * @param usePrimitives * Whether to use primitives (<code>long</code>, * <code>double</code> , <code>boolean</code>) instead of wrapper * types where possible when generating bean properties (has the * side-effect of making those properties non-null). * <p> * Default: <code>false</code>. */ public void setUsePrimitives(boolean usePrimitives) { this.usePrimitives = usePrimitives; } /** * Sets the 'useLongIntegers' property of this class * * @param useLongIntegers * Whether to use the java type <code>long</code> (or * {@link java.lang.Long}) instead of <code>int</code> (or * {@link java.lang.Integer}) when representing the JSON Schema * type 'integer'. */ public void setUseLongIntegers(boolean useLongIntegers) { this.useLongIntegers = useLongIntegers; } /** * Sets schema file (or directory containing schema files) that should be * used for input. * * @param source * Location of the JSON Schema file(s). Note: this may refer to a * single file or a directory of files. */ public void setSource(File source) { this.source = source; } /** * Sets the target (output) directory for generated source files. * * @param targetDirectory * Target directory for generated Java source files. */ public void setTargetDirectory(File targetDirectory) { this.targetDirectory = targetDirectory; } /** * Sets the target package for generated types. * * @param targetPackage * Package name used for generated Java classes (for types where * a fully qualified name has not been supplied in the schema * using the 'javaType' property). */ public void setTargetPackage(String targetPackage) { this.targetPackage = targetPackage; } /** * Sets the 'skip' property of this task. * * @param skip * whether to skip execution of this task */ public void setSkip(boolean skip) { this.skip = skip; } /** * @param propertyWordDelimiters * a string containing all of the characters that should be * considered as word delimiters when creating Java Bean property * names from JSON property names. If blank or not set, JSON * properties will be considered to contain a single word when * creating Java Bean property names. */ public void setPropertyWordDelimiters(String propertyWordDelimiters) { this.propertyWordDelimiters = defaultString(propertyWordDelimiters).toCharArray(); } /** * Sets the 'includeHashcodeAndEquals' property of this class * * @param includeHashcodeAndEquals * Whether to include <code>hashCode</code> and * <code>equals</code> methods in generated Java types. */ public void setIncludeHashcodeAndEquals(boolean includeHashcodeAndEquals) { this.includeHashcodeAndEquals = includeHashcodeAndEquals; } /** * Sets the 'includeToString' property of this class * * @param includeToString * Whether to include a <code>toString</code> method in generated * Java types. */ public void setIncludeToString(boolean includeToString) { this.includeToString = includeToString; } /** * Sets the 'annotationStyle' property of this class * * @param annotationStyle * The style of annotations to use in the generated Java types. */ public void setAnnotationStyle(AnnotationStyle annotationStyle) { this.annotationStyle = annotationStyle; } /** * Sets the 'customAnnotator' property of this class * * @param customAnnotator * A custom annotator to use to annotate the generated types */ @SuppressWarnings("unchecked") public void setCustomAnnotator(String customAnnotator) { if (isNotBlank(customAnnotator)) { try { this.customAnnotator = (Class<? extends Annotator>) Class.forName(customAnnotator); } catch (ClassNotFoundException e) { throw new IllegalArgumentException(e); } } else { this.customAnnotator = NoopAnnotator.class; } } /** * Sets the 'includeJsr303Annotations' property of this class * * @param includeJsr303Annotations * Whether to include <a * href="http://jcp.org/en/jsr/detail?id=303">JSR-303</a> * annotations (for schema rules like minimum, maximum, etc) in * generated Java types. */ public void setIncludeJsr303Annotations(boolean includeJsr303Annotations) { this.includeJsr303Annotations = includeJsr303Annotations; } /** * Sets the 'sourceType' property of this class * * @param sourceType * The type of input documents that will be read * <p> * Supported values: * <ul> * <li><code>jsonschema</code></li> * <li><code>json</code></li> * </ul> */ public void setSourceType(SourceType sourceType) { this.sourceType = sourceType; } /** * Sets the 'removeOldOutput' property of this class * * @param removeOldOutput * Whether to empty the target directory before generation * occurs, to clear out all source files that have been generated * previously. <strong>Be warned</strong>, when activated this * option will cause jsonschema2pojo to <strong>indiscriminately * delete the entire contents of the target directory (all files * and folders)</strong> before it begins generating sources. */ public void setRemoveOldOutput(boolean removeOldOutput) { this.removeOldOutput = removeOldOutput; } @Override public boolean isGenerateBuilders() { return generateBuilders; } @Override public boolean isUsePrimitives() { return usePrimitives; } @Override public Iterator<File> getSource() { return Collections.singleton(source).iterator(); } @Override public File getTargetDirectory() { return targetDirectory; } @Override public String getTargetPackage() { return targetPackage; } @Override public char[] getPropertyWordDelimiters() { return propertyWordDelimiters.clone(); } /** * Should this task be skipped? (don't read schemas, don't generate types) * * @return <code>true</code> if this task is disabled */ public boolean isSkip() { return skip; } @Override public boolean isUseLongIntegers() { return useLongIntegers; } @Override public boolean isIncludeHashcodeAndEquals() { return includeHashcodeAndEquals; } @Override public boolean isIncludeToString() { return includeToString; } @Override public AnnotationStyle getAnnotationStyle() { return annotationStyle; } @Override public Class<? extends Annotator> getCustomAnnotator() { return customAnnotator; } @Override public boolean isIncludeJsr303Annotations() { return includeJsr303Annotations; } @Override public SourceType getSourceType() { return sourceType; } public Path createClasspath() { if (classpath == null) { classpath = new Path(getProject()); } return classpath.createPath(); } public void setClasspath(Path classpath) { if (classpath == null) { this.classpath = classpath; } else { this.classpath.append(classpath); } } public void setClasspathRef(Reference classpathRef) { createClasspath().setRefid(classpathRef); } public Path getClasspath() { return (classpath == null) ? new Path(getProject()) : classpath; } @Override public boolean isRemoveOldOutput() { return removeOldOutput; } }