Skip to content
This repository has been archived by the owner on May 26, 2020. It is now read-only.

Commit

Permalink
allow plugins to have a factory method for instantiation
Browse files Browse the repository at this point in the history
  • Loading branch information
amckenzie committed Sep 22, 2017
1 parent 1510143 commit bf61d06
Show file tree
Hide file tree
Showing 32 changed files with 1,596 additions and 427 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public class GeneratorUtil {
);
private List<TypeModifyingPlugin> typeModifyingPlugins = asList(
new SupportJavaOptionalsPlugin(),
new CustomReturnTypePlugin());
CustomReturnTypePlugin.create());

public GeneratorUtil withIgnoredClassNames(final List<String> ignoredClassNames) {
this.ignoredClassNames = ignoredClassNames;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

/**
* Plugin for adding the {@link Event} annotation to the top of the root POJO.
* The name of the event will be taked from the json schema document
* The name of the event will be taken from the json schema document
*/
public class AddEventAnnotationToClassPlugin implements ClassModifyingPlugin {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import uk.gov.justice.generation.pojo.generators.TypeNameProvider;
import uk.gov.justice.generation.pojo.plugin.PluginProvider;
import uk.gov.justice.generation.pojo.plugin.PluginProviderFactory;
import uk.gov.justice.generation.pojo.plugin.PluginProviderFactoryFactory;
import uk.gov.justice.generation.pojo.plugin.TypeNamePluginProcessor;
import uk.gov.justice.generation.pojo.plugin.classmodifying.PluginContext;
import uk.gov.justice.generation.pojo.visitable.VisitableFactory;
Expand Down Expand Up @@ -44,6 +45,7 @@ public class SchemaPojoGenerator implements Generator<File> {
private final SchemaLoader schemaLoader = new SchemaLoader();
private final VisitableFactory visitableFactory = new VisitableFactory();
private final JavaFileSimpleNameLister javaFileSimpleNameLister = new JavaFileSimpleNameLister();
private final PluginProviderFactoryFactory pluginProviderFactoryFactory = new PluginProviderFactoryFactory();

/**
* Run the pojo generation based on the specified json schema file
Expand Down Expand Up @@ -80,7 +82,7 @@ public void run(final File jsonSchemaFile, final GeneratorConfig generatorConfig
}

private PluginProvider createPluginProvider(final GeneratorConfig generatorConfig) {
final PluginProviderFactory pluginProviderFactory = new PluginProviderFactory();
final PluginProviderFactory pluginProviderFactory = pluginProviderFactoryFactory.create();
return pluginProviderFactory.createFor(generatorConfig);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package uk.gov.justice.generation.pojo.plugin;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

/**
* Marks a public static method on a plugin as a factory method for creating an instance
* of the plugin
*/
@Documented
@Target(METHOD)
@Retention(RUNTIME)
public @interface FactoryMethod {
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
package uk.gov.justice.generation.pojo.plugin;

import static java.lang.String.format;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;

import uk.gov.justice.generation.pojo.plugin.classmodifying.AddFieldsAndMethodsToClassPlugin;
import uk.gov.justice.generation.pojo.plugin.classmodifying.ClassModifyingPlugin;
import uk.gov.justice.generation.pojo.plugin.classmodifying.GenerateBuilderForClassPlugin;
import uk.gov.justice.generation.pojo.plugin.classmodifying.builder.BuilderGeneratorFactory;
import uk.gov.justice.generation.pojo.plugin.namegeneratable.NameGeneratablePlugin;
import uk.gov.justice.generation.pojo.plugin.namegeneratable.RootNameGeneratorPlugin;
import uk.gov.justice.generation.pojo.plugin.factory.AllPluginsInstantiator;
import uk.gov.justice.generation.pojo.plugin.factory.ClassModifyingPluginsSelector;
import uk.gov.justice.generation.pojo.plugin.factory.NameGeneratingPluginFactory;
import uk.gov.justice.generation.pojo.plugin.factory.PluginTypeSorter;
import uk.gov.justice.generation.pojo.plugin.factory.PluginsFromClassnameListFactory;
import uk.gov.justice.generation.pojo.plugin.factory.TypeModifyingPluginsSelector;
import uk.gov.justice.generation.pojo.plugin.typemodifying.TypeModifyingPlugin;
import uk.gov.justice.maven.generator.io.files.parser.core.GeneratorConfig;

import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

/**
* Creates a {@link PluginProvider} for both {@link ClassModifyingPlugin} and {@link
Expand Down Expand Up @@ -72,141 +68,45 @@
*/
public class PluginProviderFactory {

private static final String EXCLUDE_DEFAULT_PROPERTY = "excludeDefaultPlugins";
private static final String PLUGINS_PROPERTY = "plugins";

private static final Class<ClassModifyingPlugin> CLASS_MODIFYING_PLUGIN = ClassModifyingPlugin.class;
private static final Class<TypeModifyingPlugin> TYPE_MODIFYING_PLUGIN = TypeModifyingPlugin.class;
private static final Class<NameGeneratablePlugin> NAME_GENERATABLE_PLUGIN = NameGeneratablePlugin.class;

private static final String UNABLE_TO_CREATE_INSTANCE_MESSAGE = "Unable to create instance of pojo plugin with class name %s";
private static final String INCORRECT_CLASS_TYPE_MESSAGE = "Incorrect Class Type, Class name: %s, does not implement ClassModifyingPlugin or TypeModifyingPlugin or NameGeneratablePlugin.";
private static final int FIRST_INDEX = 0;
private final NameGeneratingPluginFactory nameGeneratingPluginFactory;
private final ClassModifyingPluginsSelector classModifyingPluginsSelector;
private final TypeModifyingPluginsSelector typeModifyingPluginsSelector;
private final PluginTypeSorter pluginTypeSorter;
private final AllPluginsInstantiator allPluginsInstantiator;
private final PluginsFromClassnameListFactory parsePluginNames;

public PluginProviderFactory(
final NameGeneratingPluginFactory nameGeneratingPluginFactory,
final ClassModifyingPluginsSelector classModifyingPluginsSelector,
final TypeModifyingPluginsSelector typeModifyingPluginsSelector,
final PluginTypeSorter pluginTypeSorter,
final AllPluginsInstantiator allPluginsInstantiator,
final PluginsFromClassnameListFactory parsePluginNames) {
this.nameGeneratingPluginFactory = nameGeneratingPluginFactory;
this.classModifyingPluginsSelector = classModifyingPluginsSelector;
this.typeModifyingPluginsSelector = typeModifyingPluginsSelector;
this.pluginTypeSorter = pluginTypeSorter;
this.allPluginsInstantiator = allPluginsInstantiator;
this.parsePluginNames = parsePluginNames;
}

/**
* Create a {@link PluginProvider} using the settings from the {@link GeneratorConfig}
*
* @param generatorConfig the generatorConfig suppying the generatorProperties
* @param generatorConfig the generatorConfig supplying the generatorProperties
* @return a {@link PluginProvider} instance
*/
public PluginProvider createFor(final GeneratorConfig generatorConfig) {
final Map<String, String> generatorProperties = generatorConfig.getGeneratorProperties();
final Map<Class<?>, List<Object>> pluginTypes = partitionPluginsAccordingToType(generatorProperties);

return new ModifyingPluginProvider(
defaultAndUserDefinedClassModifyingPlugins(generatorProperties, pluginTypes),
typeModifyingPlugins(pluginTypes),
defaultOrUserDefinedNameGeneratablePlugin(pluginTypes));
}

private NameGeneratablePlugin defaultOrUserDefinedNameGeneratablePlugin(final Map<Class<?>, List<Object>> pluginTypes) {
if (pluginTypes.containsKey(NAME_GENERATABLE_PLUGIN)) {
final List<Object> nameGeneratablePlugins = pluginTypes.get(NAME_GENERATABLE_PLUGIN);

if (nameGeneratablePlugins.size() > 1) {
final List<String> pluginNames = nameGeneratablePlugins.stream().map(plugin -> plugin.getClass().getSimpleName()).collect(toList());
throw new PluginProviderException(format("Multiple NameGeneratablePlugin identified, please supply only one. List: %s", pluginNames));
}

return (NameGeneratablePlugin) nameGeneratablePlugins.get(FIRST_INDEX);
}

return new RootNameGeneratorPlugin();
}

private Map<Class<?>, List<Object>> partitionPluginsAccordingToType(final Map<String, String> generatorProperties) {
return allInstancesOfPluginsFrom(generatorProperties)
.collect(groupingBy(this::groupByPluginInterface));
}

private Class<?> groupByPluginInterface(final Object plugin) {

final List<Class<?>> classList = asList(plugin.getClass().getInterfaces());

if (classList.contains(CLASS_MODIFYING_PLUGIN)) {
return CLASS_MODIFYING_PLUGIN;
}

if (classList.contains(TYPE_MODIFYING_PLUGIN)) {
return TYPE_MODIFYING_PLUGIN;
}

if (classList.contains(NAME_GENERATABLE_PLUGIN)) {
return NAME_GENERATABLE_PLUGIN;
}

throw new PluginProviderException(format(INCORRECT_CLASS_TYPE_MESSAGE, plugin.getClass().getName()));
}

private List<ClassModifyingPlugin> defaultAndUserDefinedClassModifyingPlugins(final Map<String, String> generatorProperties,
final Map<Class<?>, List<Object>> pluginTypes) {
return Stream
.concat(
defaultClassModifyingPlugins(generatorProperties),
userDefinedClassModifyingPlugins(pluginTypes))
.collect(toList());
}

private List<TypeModifyingPlugin> typeModifyingPlugins(final Map<Class<?>, List<Object>> pluginTypes) {
if (pluginTypes.containsKey(TYPE_MODIFYING_PLUGIN)) {
return pluginTypes.get(TYPE_MODIFYING_PLUGIN)
.stream()
.map(plugin -> (TypeModifyingPlugin) plugin)
.collect(toList());
}

return emptyList();
}

private Stream<ClassModifyingPlugin> userDefinedClassModifyingPlugins(final Map<Class<?>, List<Object>> pluginTypes) {
if (pluginTypes.containsKey(CLASS_MODIFYING_PLUGIN)) {
return pluginTypes.get(CLASS_MODIFYING_PLUGIN)
.stream()
.map(plugin -> (ClassModifyingPlugin) plugin);
}

return Stream.empty();
}

private Stream<ClassModifyingPlugin> defaultClassModifyingPlugins(final Map<String, String> generatorProperties) {
if (isExcludeDefaultPlugins(generatorProperties)) {
return Stream.empty();
}

return Stream.of(
new AddFieldsAndMethodsToClassPlugin(),
new GenerateBuilderForClassPlugin(new BuilderGeneratorFactory()));
}

private boolean isExcludeDefaultPlugins(final Map<String, String> generatorProperties) {
if (generatorProperties.containsKey(EXCLUDE_DEFAULT_PROPERTY)) {
return Boolean.valueOf(generatorProperties.get(EXCLUDE_DEFAULT_PROPERTY));
}

return false;
}

private Stream<Object> allInstancesOfPluginsFrom(final Map<String, String> generatorProperties) {
if (generatorProperties.containsKey(PLUGINS_PROPERTY)) {
final String pluginValues = generatorProperties.get(PLUGINS_PROPERTY);

if (!pluginValues.isEmpty()) {
final String[] plugins = pluginValues.split(",");

return Stream.of(plugins)
.map(this::pluginInstance);
}
}

return Stream.empty();
}
final Map<String, String> generatorProperties = generatorConfig.getGeneratorProperties();
final List<String> pluginNames = parsePluginNames.parsePluginNames(generatorProperties);
final List<Object> plugins = allPluginsInstantiator.instantiate(pluginNames);

private Object pluginInstance(final String className) {
final Map<Class<?>, List<Object>> pluginTypes = pluginTypeSorter.sortByType(plugins);

try {
return Class.forName(className.trim()).newInstance();
} catch (final InstantiationException | IllegalAccessException | ClassNotFoundException e) {
throw new PluginProviderException(format(UNABLE_TO_CREATE_INSTANCE_MESSAGE, className), e);
}
return new ModifyingPluginProvider(
classModifyingPluginsSelector.selectFrom(pluginTypes, generatorProperties),
typeModifyingPluginsSelector.selectFrom(pluginTypes),
nameGeneratingPluginFactory.create(pluginTypes));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package uk.gov.justice.generation.pojo.plugin;

import uk.gov.justice.generation.pojo.plugin.factory.AllPluginsInstantiator;
import uk.gov.justice.generation.pojo.plugin.factory.ClassModifyingPluginsSelector;
import uk.gov.justice.generation.pojo.plugin.factory.DefaultPluginsProvider;
import uk.gov.justice.generation.pojo.plugin.factory.ExcludeDefaultPluginsSwitch;
import uk.gov.justice.generation.pojo.plugin.factory.Instantiator;
import uk.gov.justice.generation.pojo.plugin.factory.NameGeneratingPluginFactory;
import uk.gov.justice.generation.pojo.plugin.factory.PluginInstantiator;
import uk.gov.justice.generation.pojo.plugin.factory.PluginTypeSorter;
import uk.gov.justice.generation.pojo.plugin.factory.PluginsFromClassnameListFactory;
import uk.gov.justice.generation.pojo.plugin.factory.TypeModifyingPluginsSelector;

public class PluginProviderFactoryFactory {

public PluginProviderFactory create() {

final ExcludeDefaultPluginsSwitch excludeDefaultPluginsSwitch = new ExcludeDefaultPluginsSwitch();
final DefaultPluginsProvider defaultPluginsProvider = new DefaultPluginsProvider();

return new PluginProviderFactory(
new NameGeneratingPluginFactory(),
new ClassModifyingPluginsSelector(excludeDefaultPluginsSwitch, defaultPluginsProvider),
new TypeModifyingPluginsSelector(),
new PluginTypeSorter(),
new AllPluginsInstantiator(new PluginInstantiator(new Instantiator())),
new PluginsFromClassnameListFactory()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import uk.gov.justice.generation.pojo.dom.ClassDefinition;
import uk.gov.justice.generation.pojo.dom.Definition;
import uk.gov.justice.generation.pojo.plugin.FactoryMethod;
import uk.gov.justice.generation.pojo.plugin.classmodifying.properties.AdditionalPropertiesDeterminer;

import java.util.List;
Expand Down Expand Up @@ -42,6 +43,11 @@ public AddHashcodeAndEqualsPlugin(final AdditionalPropertiesDeterminer additiona
this.additionalPropertiesDeterminer = additionalPropertiesDeterminer;
}

@FactoryMethod
public static AddHashcodeAndEqualsPlugin newInstance() {
return new AddHashcodeAndEqualsPlugin(new AdditionalPropertiesDeterminer());
}

@Override
public TypeSpec.Builder generateWith(
final TypeSpec.Builder classBuilder,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package uk.gov.justice.generation.pojo.plugin.factory;

import static java.util.stream.Collectors.toList;

import java.util.List;

public class AllPluginsInstantiator {

private final PluginInstantiator pluginInstantiator;

public AllPluginsInstantiator(final PluginInstantiator pluginInstantiator) {
this.pluginInstantiator = pluginInstantiator;
}

public List<Object> instantiate(final List<String> pluginNames) {
return pluginNames
.stream()
.map(pluginInstantiator::instantiate)
.collect(toList());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package uk.gov.justice.generation.pojo.plugin.factory;

import static java.util.stream.Collectors.toList;
import static java.util.stream.Stream.concat;

import uk.gov.justice.generation.pojo.plugin.classmodifying.ClassModifyingPlugin;

import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

public class ClassModifyingPluginsSelector {

private static final Class<ClassModifyingPlugin> CLASS_MODIFYING_PLUGIN = ClassModifyingPlugin.class;

private final ExcludeDefaultPluginsSwitch excludeDefaultPluginsSwitch;
private final DefaultPluginsProvider defaultPluginsProvider;

public ClassModifyingPluginsSelector(
final ExcludeDefaultPluginsSwitch excludeDefaultPluginsSwitch,
final DefaultPluginsProvider defaultPluginsProvider) {
this.excludeDefaultPluginsSwitch = excludeDefaultPluginsSwitch;
this.defaultPluginsProvider = defaultPluginsProvider;
}

public List<ClassModifyingPlugin> selectFrom(final Map<Class<?>, List<Object>> pluginTypes, final Map<String, String> generatorProperties) {
return concat(
defaultClassModifyingPlugins(generatorProperties),
userDefinedClassModifyingPlugins(pluginTypes)
).collect(toList());
}

private Stream<ClassModifyingPlugin> userDefinedClassModifyingPlugins(final Map<Class<?>, List<Object>> pluginTypes) {
if (pluginTypes.containsKey(CLASS_MODIFYING_PLUGIN)) {
return pluginTypes.get(CLASS_MODIFYING_PLUGIN)
.stream()
.map(plugin -> (ClassModifyingPlugin) plugin);
}

return Stream.empty();
}

private Stream<ClassModifyingPlugin> defaultClassModifyingPlugins(final Map<String, String> generatorProperties) {
if (excludeDefaultPluginsSwitch.shouldExcludeDefaultPlugins(generatorProperties)) {
return Stream.empty();
}

return defaultPluginsProvider.getDefaultPlugins().stream();
}
}
Loading

0 comments on commit bf61d06

Please sign in to comment.