Advertisement
Guest User

Untitled

a guest
Apr 8th, 2020
248
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 24.47 KB | None | 0 0
  1. package ru.ifmo.rain.dorofeev.implementor;
  2.  
  3. import info.kgeorgiy.java.advanced.implementor.ImplerException;
  4. import info.kgeorgiy.java.advanced.implementor.JarImpler;
  5.  
  6. import javax.tools.JavaCompiler;
  7. import javax.tools.ToolProvider;
  8. import java.io.File;
  9. import java.io.IOException;
  10. import java.lang.reflect.*;
  11. import java.net.URISyntaxException;
  12. import java.nio.file.Files;
  13. import java.nio.file.Path;
  14. import java.nio.file.Paths;
  15. import java.security.CodeSource;
  16. import java.util.*;
  17. import java.util.jar.Attributes;
  18. import java.util.jar.JarOutputStream;
  19. import java.util.jar.Manifest;
  20. import java.util.stream.Collectors;
  21. import java.util.zip.ZipEntry;
  22.  
  23.  
  24. /**
  25.  * @author Mark Dorofeev
  26.  */
  27. public class JarImplementor implements JarImpler {
  28.  
  29.     public static class StringConstants {
  30.         /**
  31.          * File name extension for source file.
  32.          */
  33.         public  static final String JAVA = "java";
  34.         /**
  35.          * Suffix of generated class name.
  36.          */
  37.         public  static final String CLASS_NAME_SUFFIX = "Impl";
  38.         /**
  39.          * Empty string token.
  40.          */
  41.         public  static final String EMPTY = "";
  42.         /**
  43.          * Space token.
  44.          */
  45.         public  static final String SPACE = " ";
  46.         /**
  47.          * Tabulation token.
  48.          */
  49.         public  static final String TAB = "\t";
  50.         /**
  51.          * New line token.
  52.          */
  53.         public  static final String NEWLINE = System.lineSeparator();
  54.         /**
  55.          * Double new line token.
  56.          */
  57.         public  static final String DOUBLE_NEWLINE = NEWLINE + NEWLINE;
  58.         /**
  59.          * Colon token.
  60.          */
  61.         public  static final String COLON = ";";
  62.         /**
  63.          * Open curly bracket token.
  64.          */
  65.         public  static final String CURLY_OPEN = "{";
  66.         /**
  67.          * Close curly bracket token.
  68.          */
  69.         public  static final String CURLY_CLOSE = "}";
  70.         /**
  71.          * Open bracket token.
  72.          */
  73.         public  static final String OPEN = "(";
  74.         /**
  75.          * Close bracket token.
  76.          */
  77.         public  static final String CLOSE = ")";
  78.         /**
  79.          * Comma token.
  80.          */
  81.         public  static final String COMMA = ",";
  82.         /**
  83.          * Null token.
  84.          */
  85.         public  static final String NULL = "null";
  86.         /**
  87.          * True token.
  88.          */
  89.         public  static final String TRUE = "true";
  90.         /**
  91.          * Zero token.
  92.          */
  93.         public  static final String ZERO = "0";
  94.  
  95.         /**
  96.          * String representation of keyword <code>package</code>
  97.          */
  98.         public static final String PACKAGE = "package ";
  99.         /**
  100.          * String representation of keyword <code>class</code>
  101.          */
  102.         public  static final String CLASS = "class ";
  103.         /**
  104.          * String representation of keyword <code>implements</code>
  105.          */
  106.         public  static final String IMPLEMENTS = "implements ";
  107.         /**
  108.          * String representation of keyword <code>extends</code>
  109.          */
  110.         public  static final String EXTENDS = "extends ";
  111.         /**
  112.          * String representation of keyword <code>throws</code>
  113.          */
  114.         public  static final String THROWS = "throws ";
  115.         /**
  116.          * String representation of keyword <code>public</code>
  117.          */
  118.         public  static final String PUBLIC = "public ";
  119.         /**
  120.          * String representation of keyword <code>return</code>
  121.          */
  122.         public  static final String RETURN = "return ";
  123.         /**
  124.          * String representation of keyword <code>super</code>
  125.          */
  126.         public  static final String SUPER = "super";
  127.  
  128.     }
  129.  
  130.     /**
  131.      * Stores implementation of generated class
  132.      */
  133.     private StringBuilder classImplementation;
  134.  
  135.  
  136.     /**
  137.      * Return package declaration with the following format:
  138.      * <code>package a.b.c;</code>.
  139.      *
  140.      * @param token target type token
  141.      * @return package declaration
  142.      */
  143.     private String getPackageDeclaration(Class<?> token) {
  144.         if (token.getPackageName() != null) {
  145.             return StringConstants.PACKAGE + token.getPackageName() + StringConstants.COLON + StringConstants.DOUBLE_NEWLINE;
  146.         }
  147.         return StringConstants.EMPTY;
  148.     }
  149.  
  150.     /**
  151.      * Return class declaration with the following format:
  152.      * <code>class className;</code>
  153.      *
  154.      * @param token target type token
  155.      * @return class declaration
  156.      */
  157.     private String getClassDeclaration(Class<?> token) {
  158.         return StringConstants.PUBLIC + StringConstants.CLASS + token.getSimpleName() + StringConstants.CLASS_NAME_SUFFIX + StringConstants.SPACE
  159.                 + (token.isInterface() ? StringConstants.IMPLEMENTS : StringConstants.EXTENDS)
  160.                 + token.getCanonicalName()
  161.                 + StringConstants.SPACE + StringConstants.CURLY_OPEN + System.lineSeparator();
  162.     }
  163.  
  164.     /**
  165.      * Returns full path of the file with target class implementation.
  166.      *
  167.      * @param path initial path
  168.      * @param token target type token
  169.      * @param extension extension of target source file
  170.      * @return full path to the file with target class implementation
  171.      */
  172.     private Path getFilePath(Path path, Class<?> token, String extension) {
  173.         return path.resolve(token.getPackageName().replace('.', File.separatorChar)).resolve(token.getSimpleName() + StringConstants.CLASS_NAME_SUFFIX + '.' + extension);
  174.     }
  175.  
  176.     /**
  177.      * Returns full path of the file with target class implementation.
  178.      *
  179.      * @param token     target type token
  180.      * @return full path to the file with target class implementation
  181.      */
  182.     private String getFilePath1(Class<?> token) {
  183.         return Paths.get("").resolve(token.getPackageName().replace('.', '/')).resolve(token.getSimpleName()).toString().replace('\\', '/');
  184.     }
  185.  
  186.     /**
  187.      * Creates a directory for output file if it doesn't exist.
  188.      *
  189.      * @param path target path
  190.      * @throws ImplerException if an {@link IOException} has occurred
  191.      */
  192.     private void createDirectories(Path path) throws ImplerException {
  193.         if (path.getParent() != null) {
  194.             try {
  195.                 Files.createDirectories(path.getParent());
  196.             } catch (IOException e) {
  197.                 throw new ImplerException(String.format("Unable to create directories for output file with path: %s", path.toString()), e);
  198.             }
  199.         }
  200.     }
  201.  
  202.     /**
  203.      * Compiles a provided source file using system java compiler.
  204.      * This method uses class path used when launching the program so make sure you specified
  205.      * all the paths (including modules) in the <code>-classpath</code> flag.
  206.      *
  207.      * @param token target type token
  208.      * @param path target source file
  209.      * @throws ImplerException if compilation error has occurred when compiling target source file.
  210.      */
  211.     private void compile(Class<?> token, Path path) throws ImplerException {
  212.         String cp;
  213.         try {
  214.             CodeSource source = token.getProtectionDomain().getCodeSource();
  215.             if (source == null) {
  216.                 cp = ".";
  217.             } else {
  218.                 cp = Path.of(source.getLocation().toURI()).toString();
  219.             }
  220.         } catch (final URISyntaxException e) {
  221.             throw new ImplerException("Cannot resolve classpath" + e.getMessage());
  222.         }
  223.  
  224.         JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
  225.         String[] args = new String[]{"-encoding", "UTF-8",
  226.                 "-cp",
  227.                 path.toString() + File.pathSeparator +
  228.                         cp,
  229.                 Path.of(path.toString(), getFilePath1(token) + "Impl.java").toString()
  230.         };
  231.  
  232.         if (javaCompiler == null || javaCompiler.run(null, null, null, args) != 0) {
  233.             throw new ImplerException("Error during compiling generated java classes");
  234.         }
  235.     }
  236.  
  237.  
  238.     /**
  239.      * Creates a <code>.jar</code> file.
  240.      * Note, that the obtained file is not executable and contains only one <code>.class</code> file.
  241.      *
  242.      * @param token target type token
  243.      * @param path target path for the output <code>jar</code> file
  244.      * @param sourcePath source file of <code>.class</code> file
  245.      * @throws ImplerException if an internal {@link IOException} has occurred
  246.      */
  247.     private void createJar(Class<?> token, Path path, Path sourcePath) throws ImplerException {
  248.         Manifest manifest = new Manifest();
  249.         Attributes attributes = manifest.getMainAttributes();
  250.         attributes.put(Attributes.Name.MANIFEST_VERSION, "1.0");
  251.  
  252.         try (JarOutputStream stream = new JarOutputStream(Files.newOutputStream(path), manifest)) {
  253.             String implementationPath = getFilePath1(token) + "Impl.class";
  254.             stream.putNextEntry(new ZipEntry(implementationPath));
  255.             Files.copy(Path.of(sourcePath.toString(), implementationPath), stream);
  256.  
  257.         } catch (IOException e) {
  258.             throw new ImplerException("Writing a jar file error ", e);
  259.         }
  260.     }
  261.  
  262.     /**
  263.      * Deletes a directory denoted by the path provided.
  264.      *
  265.      * @param path target path
  266.      * @throws IOException if an internal {@link IOException} has occurred
  267.      */
  268.     private void deleteDirectory(Path path) throws IOException {
  269.         Files.walk(path).sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete);
  270.     }
  271.  
  272.     /**
  273.      * Generates implementation of a class denoted by the provided type token and creates a <code>.jar</code>
  274.      * file which contains that implementation in the provided path.
  275.      *
  276.      * @param token target type token
  277.      * @param path target path
  278.      * @throws ImplerException if:
  279.      * <ul>
  280.      *     <li>One or more arguments are <code>null</code></li>
  281.      *     <li>Target class can't be extended</li>
  282.      *     <li>An internal {@link IOException} has occurred when handling I/O processes</li>
  283.      *     <li>There are no callable constructors in the target class</li>
  284.      * </ul>
  285.      */
  286.     @Override
  287.     public void implement(Class<?> token, Path path) throws ImplerException {
  288.         path = getFilePath(path, token, StringConstants.JAVA);
  289.         createDirectories(path);
  290.         classImplementation = new StringBuilder();
  291.         try (var writer = Files.newBufferedWriter(path)) {
  292.             generateDeclaration(token);
  293.             generateBody(token);
  294.             generateEnd();
  295.             writer.write(toUnicode(classImplementation.toString()));
  296.         } catch (IOException ignored) {
  297.             throw new ImplerException(String.format("Can't write implementation of a following class: %s", token.getCanonicalName()));
  298.         }
  299.     }
  300.  
  301.     /**
  302.      * Generates implementation of a class denoted by the provided type token and creates a <code>.jar</code> file.
  303.      *
  304.      * @param token target type token
  305.      * @param path target path
  306.      * @throws ImplerException if:
  307.      * <ul>
  308.      *     <li>One or more arguments are <code>null</code></li>
  309.      *     <li>Target class can't be extended</li>
  310.      *     <li>An internal {@link IOException} has occurred when handling I/O processes</li>
  311.      *     <li>{@link javax.tools.JavaCompiler} failed to compile target source file</li>
  312.      *     <li>There are no callable constructors in the target class</li>
  313.      * </ul>
  314.      */
  315.     @Override
  316.     public void implementJar(Class<?> token, Path path) throws ImplerException {
  317.         Path sourcePath;
  318.         createDirectories(path);
  319.  
  320.         try {
  321.             sourcePath = Files.createTempDirectory(path.toAbsolutePath().getParent(), "temp");
  322.         } catch (IOException e) {
  323.             throw new ImplerException("Can't create a temporary directory.", e);
  324.         }
  325.  
  326.         try {
  327.             implement(token, sourcePath);
  328.             compile(token, sourcePath);
  329.             createJar(token, path, sourcePath);
  330.         } finally {
  331.             try {
  332.                 deleteDirectory(sourcePath);
  333.             } catch (IOException e) {
  334.                 System.err.println("Can't delete the temporary directory.");
  335.             }
  336.         }
  337.     }
  338.  
  339.     /**
  340.      * Generates header of the generated class.
  341.      * Header contains <code>package</code> declaration formed using {@link #getPackageDeclaration(Class)}
  342.      * and <code>class</code> declaration formed using {@link #getClassDeclaration(Class)}
  343.      *
  344.      * @param token target type token
  345.      */
  346.     private void generateDeclaration(Class<?> token) {
  347.         classImplementation.append(getPackageDeclaration(token));
  348.         classImplementation.append(getClassDeclaration(token));
  349.     }
  350.  
  351.     /**
  352.      * Generates body of the generated class.
  353.      * Body contains constructors' (only if the following class is not an interface) and abstract methods'
  354.      * implementations.
  355.      *
  356.      * @param token target type token
  357.      * @throws ImplerException if an internal {@link IOException} has occurred
  358.      */
  359.     private void generateBody(Class<?> token) throws ImplerException {
  360.         if (!token.isInterface()) {
  361.             generateConstructors(token);
  362.         }
  363.         generateAbstractMethods(token);
  364.     }
  365.  
  366.  
  367.     /**
  368.      * Generates footer of the generated class.
  369.      */
  370.     private void generateEnd() {
  371.         classImplementation.append(StringConstants.CURLY_CLOSE).append(StringConstants.DOUBLE_NEWLINE);
  372.     }
  373.  
  374.     private String getReturnTypeAndName(Executable executable) {
  375.         if (executable instanceof Method) {
  376.             Method m = (Method) executable;
  377.             return m.getReturnType().getCanonicalName() + StringConstants.SPACE + m.getName();
  378.         } else {
  379.             return executable.getDeclaringClass().getSimpleName() + StringConstants.CLASS_NAME_SUFFIX;
  380.         }
  381.     }
  382.  
  383.     /**
  384.      * Generates arguments for {@link Executable}.
  385.      * @param executable target executable
  386.      * @param withType indicates if types should be provided
  387.      * @return arguments for executable
  388.      */
  389.     private String getArguments(Executable executable, boolean withType) {
  390.         StringBuilder sb = new StringBuilder();
  391.         Parameter[] parameters = executable.getParameters();
  392.         for (Parameter parameter : parameters) {
  393.             sb.
  394.                     append(withType ? parameter.getType().getCanonicalName() : StringConstants.EMPTY)
  395.                     .append(StringConstants.SPACE).append(parameter.getName()).append(StringConstants.COMMA).append(StringConstants.SPACE);
  396.         }
  397.         return sb.length() > 0 ? sb.substring(0, sb.length() - 2) : sb.toString();
  398.     }
  399.  
  400.     /**
  401.      * Generates arguments for {@link Executable}.
  402.      * @param executable target executable
  403.      * @return arguments for executable
  404.      */
  405.     private String getArguments(Executable executable) {
  406.         return getArguments(executable, true);
  407.     }
  408.  
  409.     /**
  410.      * Generates exceptions for {@link Executable}.
  411.      * @param exceptions target exceptions
  412.      * @return exceptions for executable
  413.      */
  414.     private String getExceptions(Class<?>[] exceptions) {
  415.         StringBuilder stringBuilder = new StringBuilder();
  416.         for (Class<?> exception : exceptions) {
  417.             stringBuilder.append(exception.getCanonicalName()).append(StringConstants.COMMA + StringConstants.SPACE);
  418.         }
  419.         return stringBuilder.substring(0, stringBuilder.length() - 2);
  420.     }
  421.  
  422.     /**
  423.      * Generates return for {@link Executable}.
  424.      * @param executable target executable
  425.      * @return return for executable
  426.      */
  427.     private String getReturn(Executable executable) {
  428.         if (executable instanceof Method) {
  429.             Method m = (Method) executable;
  430.             if (m.getReturnType() == void.class) {
  431.                 return StringConstants.EMPTY;
  432.             } else if (m.getReturnType().isPrimitive()) {
  433.                 return m.getReturnType() == boolean.class ? StringConstants.TRUE : StringConstants.ZERO;
  434.             }
  435.             return StringConstants.NULL;
  436.         }
  437.         return StringConstants.EMPTY;
  438.     }
  439.  
  440.     /**
  441.      * Generates body for {@link Executable}.
  442.      * @param executable target executable
  443.      * @return body for executable
  444.      */
  445.     private String getBody(Executable executable) {
  446.         return (executable instanceof Constructor ?
  447.                 StringConstants.TAB + StringConstants.TAB + StringConstants.SUPER + StringConstants.OPEN + getArguments(executable, false) + StringConstants.CLOSE + StringConstants.COLON + StringConstants.NEWLINE : StringConstants.EMPTY) +
  448.                 StringConstants.TAB + StringConstants.TAB + StringConstants.RETURN + StringConstants.SPACE + getReturn(executable) + StringConstants.COLON;
  449.     }
  450.  
  451.     /**
  452.      * Generates implementation of an {@link Executable}.
  453.      * The executable must be either {@link Method} or {@link Constructor} to work correctly.
  454.      * Implementation contains:
  455.      * <ul>
  456.      *     <li>Access modifier</li>
  457.      *     <li>[optional] Type parameters (if it is a method)</li>
  458.      *     <li>[optional] Return type (if it is a method)</li>
  459.      *     <li>List of all checked exceptions thrown</li>
  460.      * </ul>
  461.      *
  462.      * @param executable target executable
  463.      */
  464.     private void generateExecutable(Executable executable) {
  465.         classImplementation.append(StringConstants.TAB).append(Modifier.toString(executable.getModifiers() & (Modifier.PUBLIC | Modifier.PROTECTED))).append(StringConstants.SPACE).append(getReturnTypeAndName(executable)).append(StringConstants.OPEN).append(getArguments(executable)).append(StringConstants.CLOSE).append(executable.getExceptionTypes().length == 0
  466.                 ? StringConstants.EMPTY
  467.                 : StringConstants.SPACE + StringConstants.THROWS + getExceptions(executable.getExceptionTypes()) + StringConstants.SPACE).append(StringConstants.CURLY_OPEN).append(StringConstants.NEWLINE).append(getBody(executable)).append(StringConstants.NEWLINE).append(StringConstants.TAB).append(StringConstants.CURLY_CLOSE).append(StringConstants.DOUBLE_NEWLINE);
  468.     }
  469.  
  470.     /**
  471.      * Add implementation of a constructor to the generated class.
  472.      *
  473.      * @param token target class
  474.      */
  475.     private void generateConstructors(Class<?> token) throws ImplerException {
  476.         List<Constructor<?>> constructors = Arrays.stream(token.getDeclaredConstructors()).filter(c -> !Modifier.isPrivate(c.getModifiers())).collect(Collectors.toList());
  477.         if (constructors.isEmpty()) {
  478.             throw new ImplerException(String.format("Class %s has no callable constructors", token.getSimpleName()));
  479.         }
  480.         for (Constructor<?> constructor : constructors) {
  481.             generateExecutable(constructor);
  482.         }
  483.     }
  484.  
  485.     /**
  486.      * Generates all abstract methods of target type.
  487.      *
  488.      * @param token target type token
  489.      */
  490.     private void generateAbstractMethods(Class<?> token) {
  491.         HashSet<CustomMethod> methods = new HashSet<>();
  492.         fill(methods, token);
  493.         methods.stream().filter(m -> !m.isOverridden).forEach(m -> generateExecutable(m.instance));
  494.     }
  495.  
  496.     /**
  497.      * A wrapper of {@link Method} for proper method comparing.
  498.      */
  499.     private class CustomMethod {
  500.         /**
  501.          * Instance of the method.
  502.          */
  503.         private Method instance;
  504.         /**
  505.          * A flag that shows if we need to override the method.
  506.          * It is set to <code>true</code> if we met a <code>final</code> or just not <code>abstract</code> method in
  507.          * the <code>super</code> class.
  508.          * Otherwise, it is set to <code>false</code>.
  509.          */
  510.         private boolean isOverridden;
  511.  
  512.         /**
  513.          * Constructor for the wrapper that receives instance and the flag.
  514.          *
  515.          * @param m target instance of {@link Method}
  516.          * @param isOverridden target flag
  517.          */
  518.         CustomMethod(Method m, boolean isOverridden) {
  519.             instance = m;
  520.             this.isOverridden = isOverridden;
  521.         }
  522.  
  523.         /**
  524.          * Custom {@link Object#equals(Object)} method to compare two instances of {@link Method}.
  525.          * Methods are equal if:
  526.          * <ul>
  527.          *     <li>The other method is not <code>null</code></li>
  528.          *     <li>The other method's {@link #hashCode()} is the same</li>
  529.          * </ul>
  530.          *
  531.          * @param obj target instance
  532.          * @return <code>true</code> if instances are equal, <code>false</code> otherwise
  533.          */
  534.         @Override
  535.         public boolean equals(Object obj) {
  536.             if (obj == null) return false;
  537.             if (obj instanceof CustomMethod) {
  538.                 return obj.hashCode() == hashCode();
  539.             }
  540.             return false;
  541.         }
  542.  
  543.         /**
  544.          * Calculates hash code of a {@link Method} instance
  545.          * Formula: {@link Arrays#hashCode(Object[])} of type parameters plus {@link Class#hashCode()} of
  546.          * return type plus {@link String#hashCode()} of name.
  547.          *
  548.          * @return hash code of the {@link #instance}
  549.          */
  550.         @Override
  551.         public int hashCode() {
  552.             return Arrays.hashCode(instance.getParameterTypes()) + instance.getReturnType().hashCode() + instance.getName().hashCode();
  553.         }
  554.     }
  555.  
  556.     /**
  557.      * Adds all abstract methods of the target type to {@link Set} of {@link CustomMethod}
  558.      *
  559.      * @param methods target set
  560.      * @param token target type token
  561.      */
  562.     private void fill(Set<CustomMethod> methods, Class<?> token) {
  563.         if (token == null) return;
  564.         methods.addAll(Arrays.stream(token.getDeclaredMethods()).map(m -> new CustomMethod(m, Modifier.isFinal(m.getModifiers()) || !Modifier.isAbstract(m.getModifiers()))).collect(Collectors.toSet()));
  565.         Arrays.stream(token.getInterfaces()).forEach(i -> fill(methods, i));
  566.         fill(methods, token.getSuperclass());
  567.     }
  568.  
  569.     /**
  570.      * Checks if a class can be extended.
  571.      * Note: a class can't be extended if:
  572.      * <ul>
  573.      *     <li>It is a primitive</li>
  574.      *     <li>It is final</li>
  575.      *     <li>It is array</li>
  576.      *     <li>It is enum</li>
  577.      *     <li>It is {@link Enum}</li>
  578.      * </ul>
  579.      *
  580.      * @param token target type token
  581.      * @throws ImplerException if the class can't be extended
  582.      */
  583.     private void validateClass(Class<?> token) throws ImplerException {
  584.         if (token.isPrimitive() || token.isArray() || token.isEnum() || Modifier.isFinal(token.getModifiers()) || token == Enum.class || Modifier.isPrivate(token.getModifiers())) {
  585.             throw new ImplerException(String.format("Invalid class with name: %s", token.getSimpleName()));
  586.         }
  587.     }
  588.  
  589.     /**
  590.      * Return Unicode representation of the input string.
  591.      *
  592.      * @param input input string
  593.      * @return Unicode representation of the input string
  594.      */
  595.     private String toUnicode(String input) {
  596.         StringBuilder b = new StringBuilder();
  597.         for (char c : input.toCharArray()) {
  598.             if (c >= 128) {
  599.                 b.append(String.format("\\u%04X", (int) c));
  600.             } else {
  601.                 b.append(c);
  602.             }
  603.         }
  604.         return b.toString();
  605.     }
  606.  
  607.     /**
  608.      * Entry point of the program.
  609.      * Usage: Implementor [-jar] &lt;Class name&gt; &lt;Target path&gt;
  610.      *
  611.      * @param args arguments
  612.      */
  613.     public static void main(String[] args) {
  614.         if (args == null || args[0] == null || args[1] == null || (args.length > 2 && args[2] == null)) {
  615.             System.out.println("Wrong arguments format");
  616.             return;
  617.         }
  618.  
  619.         for (String arg : args) {
  620.             if (arg == null) {
  621.                 System.out.println("Null argument appeared");
  622.                 return;
  623.             }
  624.         }
  625.  
  626.         boolean isJar = "-jar".equals(args[0]);
  627.         int offset = isJar ? 1 : 0;
  628.         String classFullName = args[offset];
  629.         String pathName = args[offset + 1];
  630.         JarImplementor implementor = new JarImplementor();
  631.         try {
  632.             Class<?> token = Class.forName(classFullName);
  633.             Path path = Paths.get(pathName);
  634.             if (isJar) {
  635.                 implementor.implementJar(token, path);
  636.             } else {
  637.                 implementor.implement(token, path);
  638.             }
  639.         } catch (ClassNotFoundException ignored) {
  640.             System.err.println(String.format("Class with name %s not found", classFullName));
  641.         } catch (ImplerException ignored) {
  642.             System.err.println(String.format("Can't generate implementation of a class with full name: %s", classFullName));
  643.         }
  644.     }
  645.  
  646. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement