All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.joda.beans.gen.BeanCodeGen Maven / Gradle / Ivy

/*
 *  Copyright 2001-present Stephen Colebourne
 *
 *  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 org.joda.beans.gen;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;

import org.joda.beans.JodaBeanUtils;

/**
 * Code generator for the beans.
 * 

* This reads in a {@code .java} file, parses it, and writes out an updated version. */ public class BeanCodeGen { /** * Main method. *

* This calls {@code System.exit}. * * @param args the arguments, not null */ public static void main(String[] args) { BeanCodeGen gen; try { gen = createFromArgs(args); } catch (RuntimeException ex) { System.out.println(ex.getMessage()); System.out.println(""); System.out.println("Code generator"); System.out.println(" Usage java org.joda.beans.gen.BeanCodeGen [file]"); System.out.println(" Options"); System.out.println(" -R process all files recursively, default false"); System.out.println(" -indent=tab use a tab for indenting, default 4 spaces"); System.out.println(" -indent=[n] use n spaces for indenting, default 4"); System.out.println(" -prefix=[p] field prefix of p should be removed, no default"); System.out.println(" -eol=[e] end of line: 'lf'/'crlf'/'cr', default System.lineSeparator"); System.out.println(" -generated add @Generated annotation to generated code"); System.out.println(" -config=[f] config file: 'jdk'/'guava', default guava"); System.out.println(" -style=[s] default bean style: 'light'/'minimal'/'full', default smart"); System.out.println(" -verbose=[v] output logging with verbosity from 0 to 3, default 1"); System.out.println(" -nowrite output messages rather than writing, default is to write"); System.exit(0); throw new InternalError("Unreachable"); } try { int changed = gen.process(); System.out.println("Finished, found " + changed + " changed files"); System.exit(0); } catch (Exception ex) { System.out.println(); ex.printStackTrace(System.out); System.exit(1); } } /** * Creates an instance of {@code BeanCodeGen} from arguments. *

* This is intended for tools and does not call {@code System.exit}. * * @param args the arguments, not null * @return the code generator, not null * @throws RuntimeException if unable to create */ public static BeanCodeGen createFromArgs(String[] args) { if (args == null) { throw new IllegalArgumentException("Arguments must not be null"); } String indent = " "; String prefix = ""; String eol = System.lineSeparator(); String defaultStyle = null; boolean recurse = false; boolean generatedAnno = false; int verbosity = 1; boolean write = true; File file = null; BeanGenConfig config = null; if (args.length == 0) { throw new IllegalArgumentException("No arguments specified"); } for (int i = 0; i < args.length - 1; i++) { String arg = args[i]; if (arg == null) { throw new IllegalArgumentException("Argument must not be null: " + Arrays.toString(args)); } if (arg.startsWith("-indent=tab")) { indent = "\t"; } else if (arg.startsWith("-indent=")) { indent = " ".substring(0, Integer.parseInt(arg.substring(8))); } else if (arg.startsWith("-prefix=")) { prefix = arg.substring(8); } else if (arg.startsWith("-eol=")) { switch (arg.substring(5)) { case "lf": eol = "\n"; break; case "crlf": eol = "\r\n"; break; case "cr": eol = "\r"; break; case "system": eol = System.lineSeparator(); break; default: throw new IllegalArgumentException("Value of 'eol' must be one of: 'lf', 'crlf', 'cr', 'system'"); } } else if (arg.equals("-R")) { recurse = true; } else if (arg.equals("-generated")) { if (generatedAnno) { throw new IllegalArgumentException("Argument 'generated' must not be specified twice: " + Arrays.toString(args)); } generatedAnno = true; } else if (arg.startsWith("-config=")) { if (config != null) { throw new IllegalArgumentException("Argument 'config' must not be specified twice: " + Arrays.toString(args)); } config = BeanGenConfig.parse(arg.substring(8)); } else if (arg.startsWith("-style=")) { if (defaultStyle != null) { throw new IllegalArgumentException("Argument 'style' must not be specified twice: " + Arrays.toString(args)); } defaultStyle = arg.substring(7); } else if (arg.startsWith("-verbose=")) { verbosity = Integer.parseInt(arg.substring(9)); } else if (arg.startsWith("-v=")) { System.out.println("Deprecated command line argument -v (use -verbose instead)"); verbosity = Integer.parseInt(arg.substring(3)); } else if (arg.equals("-nowrite")) { write = false; } else { throw new IllegalArgumentException("Unknown argument: " + arg); } } file = new File(args[args.length - 1]); List files = findFiles(file, recurse); if (config == null) { config = BeanGenConfig.parse("guava"); } config.setIndent(indent); config.setPrefix(prefix); config.setEol(eol); if (defaultStyle != null) { config.setDefaultStyle(defaultStyle); } config.setGeneratedAnno(generatedAnno); return new BeanCodeGen(files, config, verbosity, write); } /** * Finds the set of files to process. * * @param parent the root, not null * @param recurse whether to recurse * @return the files, not null */ private static List findFiles(final File parent, boolean recurse) { final List result = new ArrayList<>(); if (parent.isDirectory()) { File[] files = parent.listFiles(); files = (files != null ? files : new File[0]); for (File child : files) { if (child.isFile() && child.getName().endsWith(".java")) { result.add(child); } } if (recurse) { for (File child : files) { if (child.isDirectory() && child.getName().startsWith(".") == false) { result.addAll(findFiles(child, recurse)); } } } } else { if (parent.getName().endsWith(".java")) { result.add(parent); } } return result; } //----------------------------------------------------------------------- /** The files to process. */ private final List files; /** The configuration to use. */ private final BeanGenConfig config; /** The verbosity level. */ private final int verbosity; /** Whether to write or not. */ private final boolean write; /** * Creates the generator for a single bean. *

* To generate, use {@link #process()}. * * @param files the files to process, not null * @param config the configuration to use, not null * @param verbosity the verbosity, from 0 to 3 * @param write whether to write or not */ public BeanCodeGen(List files, BeanGenConfig config, int verbosity, boolean write) { JodaBeanUtils.notNull(files, "files"); JodaBeanUtils.notNull(config, "config"); if (verbosity < 0 || verbosity > 3) { throw new IllegalArgumentException("Invalid verbosity: " + verbosity); } this.files = files; this.config = config; this.verbosity = verbosity; this.write = write; } //----------------------------------------------------------------------- /** * Processes the file, recursing as necessary, generating the source code. *

* The number of altered files is returned. * * @return the number of changed files * @throws Exception if an error occurs */ public int process() throws Exception { int changed = 0; for (File child : files) { changed += (processFile(child) != null ? 1 : 0); } return changed; } /** * Processes the file, recursing as necessary, generating the source code. *

* The list of altered files is returned. * * @return the list of changed files, not null * @throws Exception if an error occurs */ public List processFiles() throws Exception { List changed = new ArrayList<>(); for (File child : files) { File file = processFile(child); if (file != null) { changed.add(file); } } return changed; } /** * Processes the bean, generating the code. * * @param file the file to process, not null * @return not-null if changed * @throws Exception if an error occurs */ private File processFile(File file) throws Exception { List original = readFile(file); List content = new ArrayList<>(original); BeanGen gen; try { BeanParser parser = new BeanParser(file, content, config); gen = parser.parse(); } catch (BeanCodeGenException ex) { throw ex; } catch (Exception ex) { throw new BeanCodeGenException(ex.getMessage(), ex, file); } if (gen.isBean()) { if (verbosity >= 2) { System.out.print(file + " [processing]"); } gen.process(); if (contentDiffers(content, original)) { if (write) { if (verbosity >= 2) { System.out.println(" [writing]"); } else if (verbosity == 1) { System.out.println(file + " [writing]"); } writeFile(file, content); } else { if (verbosity >= 2) { System.out.println(" [changed not written]"); } else if (verbosity == 1) { System.out.println(file + " [changed not written]"); } } return file; } else { if (verbosity >= 2) { System.out.println(" [no change]"); } } } else { gen.processNonBean(); if (contentDiffers(content, original)) { if (write) { if (verbosity >= 2) { System.out.println(" [writing]"); } else if (verbosity == 1) { System.out.println(file + " [writing]"); } writeFile(file, content); } else { if (verbosity >= 2) { System.out.println(" [changed not written]"); } else if (verbosity == 1) { System.out.println(file + " [changed not written]"); } } return file; } else { if (verbosity == 3) { System.out.println(file + " [ignored]"); } } } return null; } // checks to see if the content differs from the original // if the files differ only by @Override lines then they are considered to be equal private boolean contentDiffers(List content, List original) { Pattern overridePattern = Pattern.compile(" *[@]Override"); int contentIndex = 0; int originalIndex = 0; while (contentIndex < content.size() && originalIndex < original.size()) { String contentLine = content.get(contentIndex); String originalLine = original.get(originalIndex); if (contentLine.equals(originalLine)) { // lines match contentIndex++; originalIndex++; } else if (overridePattern.matcher(originalLine).matches()) { // original is an @Override line originalIndex++; } else { return true; } } if (contentIndex < content.size() || originalIndex < original.size()) { return true; } return false; } //----------------------------------------------------------------------- private List readFile(File file) throws Exception { List content = new ArrayList<>(100); try (BufferedReader is = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"))) { String line; while ((line = is.readLine()) != null) { content.add(line); } return content; } } private void writeFile(File file, List content) throws Exception { try (BufferedWriter os = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"))) { for (String line : content) { os.write(line); os.write(config.getEol()); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy