From 9db6cee16907e9baeb11f17dc1443851c2bad1b8 Mon Sep 17 00:00:00 2001
From: Appu Goundan <appu@google.com>
Date: Thu, 1 Feb 2018 16:26:58 -0500
Subject: [PATCH 1/4] Convert to static extension building

Change from dynamic extension populating to the usual way
of static extensions and nested configuration objects for core
flex and standard features.

The experimental source-context plugin still adds to the appengine
configuration dynamically.
---
 .../AppEngineCoreExtensionProperties.java     | 24 ++++++
 ... => AppEngineCorePluginConfiguration.java} | 64 +++++---------
 .../appengine/core/DeployExtension.java       |  2 +
 .../appengine/core/ShowConfigurationTask.java |  1 +
 .../gradle/appengine/core/ToolsExtension.java |  2 +
 .../flexible/AppEngineFlexibleExtension.java  | 70 ++++++++++++++++
 .../flexible/AppEngineFlexiblePlugin.java     | 27 +++---
 .../sourcecontext/SourceContextPlugin.java    |  8 +-
 .../standard/AppEngineStandardExtension.java  | 83 +++++++++++++++++++
 .../standard/AppEngineStandardPlugin.java     | 54 +++++++-----
 .../appengine/standard/RunExtension.java      |  2 +
 .../standard/StageStandardExtension.java      |  2 +
 .../gradle/appengine/AppEnginePluginTest.java |  7 +-
 .../flexible/AppEngineFlexiblePluginTest.java | 21 ++---
 .../SourceContextPluginTest.java              |  5 +-
 .../AppEngineStandardExtensionTest.java       | 46 ++++------
 .../standard/AppEngineStandardPluginTest.java | 20 ++---
 17 files changed, 297 insertions(+), 141 deletions(-)
 create mode 100644 src/main/java/com/google/cloud/tools/gradle/appengine/core/AppEngineCoreExtensionProperties.java
 rename src/main/java/com/google/cloud/tools/gradle/appengine/core/{AppEngineCorePlugin.java => AppEngineCorePluginConfiguration.java} (81%)
 create mode 100644 src/main/java/com/google/cloud/tools/gradle/appengine/flexible/AppEngineFlexibleExtension.java
 create mode 100644 src/main/java/com/google/cloud/tools/gradle/appengine/standard/AppEngineStandardExtension.java

diff --git a/src/main/java/com/google/cloud/tools/gradle/appengine/core/AppEngineCoreExtensionProperties.java b/src/main/java/com/google/cloud/tools/gradle/appengine/core/AppEngineCoreExtensionProperties.java
new file mode 100644
index 00000000..4cd1bd46
--- /dev/null
+++ b/src/main/java/com/google/cloud/tools/gradle/appengine/core/AppEngineCoreExtensionProperties.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2018 Google Inc. All Right Reserved.
+ *
+ * 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.google.cloud.tools.gradle.appengine.core;
+
+public interface AppEngineCoreExtensionProperties {
+  ToolsExtension getTools();
+
+  DeployExtension getDeploy();
+}
diff --git a/src/main/java/com/google/cloud/tools/gradle/appengine/core/AppEngineCorePlugin.java b/src/main/java/com/google/cloud/tools/gradle/appengine/core/AppEngineCorePluginConfiguration.java
similarity index 81%
rename from src/main/java/com/google/cloud/tools/gradle/appengine/core/AppEngineCorePlugin.java
rename to src/main/java/com/google/cloud/tools/gradle/appengine/core/AppEngineCorePluginConfiguration.java
index 7b531c90..28582816 100644
--- a/src/main/java/com/google/cloud/tools/gradle/appengine/core/AppEngineCorePlugin.java
+++ b/src/main/java/com/google/cloud/tools/gradle/appengine/core/AppEngineCorePluginConfiguration.java
@@ -19,17 +19,14 @@
 
 import org.gradle.api.Action;
 import org.gradle.api.GradleException;
-import org.gradle.api.Plugin;
 import org.gradle.api.Project;
-import org.gradle.api.Task;
-import org.gradle.api.plugins.ExtensionAware;
 import org.gradle.util.GradleVersion;
 
 /**
  * Core plugin for App Engine, contains common tasks like deploy and show configuration Also
  * instantiates the "tools" extension to specify the cloud sdk path.
  */
-public class AppEngineCorePlugin implements Plugin<Project> {
+public class AppEngineCorePluginConfiguration {
 
   public static final GradleVersion GRADLE_MIN_VERSION = GradleVersion.version("3.4.1");
 
@@ -45,21 +42,25 @@ public class AppEngineCorePlugin implements Plugin<Project> {
   public static final String SHOW_CONFIG_TASK_NAME = "appengineShowConfiguration";
 
   public static final String APPENGINE_EXTENSION = "appengine";
-  public static final String DEPLOY_EXTENSION = "deploy";
-  public static final String TOOLS_EXTENSION = "tools";
 
   private Project project;
-  private AppEngineExtension extension;
   private DeployExtension deployExtension;
   private ToolsExtension toolsExtension;
   private CloudSdkBuilderFactory cloudSdkBuilderFactory;
+  private String taskGroup;
 
-  @Override
-  public void apply(Project project) {
+  /** Configure core tasks for appengine flexible and standard project plugins. */
+  public void configureCoreProperties(
+      Project project,
+      AppEngineCoreExtensionProperties appEngineCoreExtensionProperties,
+      String taskGroup) {
     checkGradleVersion(project);
 
     this.project = project;
-    createExtensions();
+    this.taskGroup = taskGroup;
+    this.toolsExtension = appEngineCoreExtensionProperties.getTools();
+    this.deployExtension = appEngineCoreExtensionProperties.getDeploy();
+    configureCloudSdkBuilderFactory();
 
     createDeployTask();
     createDeployCronTask();
@@ -70,17 +71,7 @@ public void apply(Project project) {
     createShowConfigurationTask();
   }
 
-  private void createExtensions() {
-    extension = project.getExtensions().create(APPENGINE_EXTENSION, AppEngineExtension.class);
-    deployExtension =
-        ((ExtensionAware) extension)
-            .getExtensions()
-            .create(DEPLOY_EXTENSION, DeployExtension.class, project);
-    toolsExtension =
-        ((ExtensionAware) extension)
-            .getExtensions()
-            .create(TOOLS_EXTENSION, ToolsExtension.class, project);
-
+  private void configureCloudSdkBuilderFactory() {
     project.afterEvaluate(
         new Action<Project>() {
           @Override
@@ -100,7 +91,7 @@ private void createDeployTask() {
             new Action<DeployTask>() {
               @Override
               public void execute(final DeployTask deployTask) {
-                deployTask.setGroup(APP_ENGINE_TASK_GROUP);
+                deployTask.setGroup(taskGroup);
                 deployTask.setDescription("Deploy an App Engine application");
 
                 project.afterEvaluate(
@@ -124,7 +115,7 @@ private void createDeployCronTask() {
             new Action<DeployCronTask>() {
               @Override
               public void execute(final DeployCronTask deployTask) {
-                deployTask.setGroup(APP_ENGINE_TASK_GROUP);
+                deployTask.setGroup(taskGroup);
                 deployTask.setDescription("Deploy Cron configuration");
 
                 project.afterEvaluate(
@@ -148,7 +139,7 @@ private void createDeployDispatchTask() {
             new Action<DeployDispatchTask>() {
               @Override
               public void execute(final DeployDispatchTask deployTask) {
-                deployTask.setGroup(APP_ENGINE_TASK_GROUP);
+                deployTask.setGroup(taskGroup);
                 deployTask.setDescription("Deploy Dispatch configuration");
 
                 project.afterEvaluate(
@@ -172,7 +163,7 @@ private void createDeployDosTask() {
             new Action<DeployDosTask>() {
               @Override
               public void execute(final DeployDosTask deployTask) {
-                deployTask.setGroup(APP_ENGINE_TASK_GROUP);
+                deployTask.setGroup(taskGroup);
                 deployTask.setDescription("Deploy Dos configuration");
 
                 project.afterEvaluate(
@@ -196,7 +187,7 @@ private void createDeployIndexTask() {
             new Action<DeployIndexTask>() {
               @Override
               public void execute(final DeployIndexTask deployTask) {
-                deployTask.setGroup(APP_ENGINE_TASK_GROUP);
+                deployTask.setGroup(taskGroup);
                 deployTask.setDescription("Deploy Index configuration");
 
                 project.afterEvaluate(
@@ -220,7 +211,7 @@ private void createDeployQueueTask() {
             new Action<DeployQueueTask>() {
               @Override
               public void execute(final DeployQueueTask deployTask) {
-                deployTask.setGroup(APP_ENGINE_TASK_GROUP);
+                deployTask.setGroup(taskGroup);
                 deployTask.setDescription("Deploy Queue configuration");
 
                 project.afterEvaluate(
@@ -244,7 +235,7 @@ private void createShowConfigurationTask() {
             new Action<ShowConfigurationTask>() {
               @Override
               public void execute(final ShowConfigurationTask showConfigurationTask) {
-                showConfigurationTask.setGroup(APP_ENGINE_TASK_GROUP);
+                showConfigurationTask.setGroup(taskGroup);
                 showConfigurationTask.setDescription(
                     "Show current App Engine plugin configuration");
 
@@ -253,23 +244,6 @@ public void execute(final ShowConfigurationTask showConfigurationTask) {
             });
   }
 
-  /** Override the default task group of tasks from this plugin. */
-  public static void overrideCoreTasksGroup(Project project, final String overrideGroup) {
-    project
-        .getTasks()
-        .all(
-            new Action<Task>() {
-              @Override
-              public void execute(Task task) {
-                String oldGroup = task.getGroup();
-                if (oldGroup != null
-                    && oldGroup.equals(AppEngineCorePlugin.APP_ENGINE_TASK_GROUP)) {
-                  task.setGroup(overrideGroup);
-                }
-              }
-            });
-  }
-
   private void checkGradleVersion(Project project) {
     if (GRADLE_MIN_VERSION.compareTo(GradleVersion.current()) > 0) {
       throw new GradleException(
diff --git a/src/main/java/com/google/cloud/tools/gradle/appengine/core/DeployExtension.java b/src/main/java/com/google/cloud/tools/gradle/appengine/core/DeployExtension.java
index 5d6bd9b8..3304cebb 100644
--- a/src/main/java/com/google/cloud/tools/gradle/appengine/core/DeployExtension.java
+++ b/src/main/java/com/google/cloud/tools/gradle/appengine/core/DeployExtension.java
@@ -22,6 +22,7 @@
 import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
+import javax.inject.Inject;
 import org.gradle.api.Project;
 
 /** Extension element to define Deployable configurations for App Engine. */
@@ -41,6 +42,7 @@ public class DeployExtension
   private String version;
   private File appEngineDirectory;
 
+  @Inject
   public DeployExtension(Project gradleProject) {
     this.gradleProject = gradleProject;
   }
diff --git a/src/main/java/com/google/cloud/tools/gradle/appengine/core/ShowConfigurationTask.java b/src/main/java/com/google/cloud/tools/gradle/appengine/core/ShowConfigurationTask.java
index 80897d56..4a4de2ec 100644
--- a/src/main/java/com/google/cloud/tools/gradle/appengine/core/ShowConfigurationTask.java
+++ b/src/main/java/com/google/cloud/tools/gradle/appengine/core/ShowConfigurationTask.java
@@ -36,6 +36,7 @@
 public class ShowConfigurationTask extends DefaultTask {
 
   private String extensionId;
+  private String allowedNestedPackageSearchPath;
 
   @Input
   public String getExtensionId() {
diff --git a/src/main/java/com/google/cloud/tools/gradle/appengine/core/ToolsExtension.java b/src/main/java/com/google/cloud/tools/gradle/appengine/core/ToolsExtension.java
index bd0852bd..808959f7 100644
--- a/src/main/java/com/google/cloud/tools/gradle/appengine/core/ToolsExtension.java
+++ b/src/main/java/com/google/cloud/tools/gradle/appengine/core/ToolsExtension.java
@@ -18,6 +18,7 @@
 package com.google.cloud.tools.gradle.appengine.core;
 
 import java.io.File;
+import javax.inject.Inject;
 import org.gradle.api.Project;
 
 /** Extension element to define the location of cloud sdk tooling. */
@@ -27,6 +28,7 @@ public class ToolsExtension {
 
   private File cloudSdkHome;
 
+  @Inject
   public ToolsExtension(Project project) {
     this.project = project;
   }
diff --git a/src/main/java/com/google/cloud/tools/gradle/appengine/flexible/AppEngineFlexibleExtension.java b/src/main/java/com/google/cloud/tools/gradle/appengine/flexible/AppEngineFlexibleExtension.java
new file mode 100644
index 00000000..2ba11a33
--- /dev/null
+++ b/src/main/java/com/google/cloud/tools/gradle/appengine/flexible/AppEngineFlexibleExtension.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2018 Google Inc. All Right Reserved.
+ *
+ * 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.google.cloud.tools.gradle.appengine.flexible;
+
+import com.google.cloud.tools.gradle.appengine.core.AppEngineCoreExtensionProperties;
+import com.google.cloud.tools.gradle.appengine.core.DeployExtension;
+import com.google.cloud.tools.gradle.appengine.core.ToolsExtension;
+import org.gradle.api.Action;
+import org.gradle.api.Project;
+import org.gradle.api.plugins.ExtensionAware;
+
+public class AppEngineFlexibleExtension implements AppEngineCoreExtensionProperties {
+  private ToolsExtension tools;
+  private DeployExtension deploy;
+  private StageFlexibleExtension stage;
+
+  /**
+   * Create nested configuration blocks as Extensions.
+   */
+  public void createSubExtensions(Project project) {
+    tools = ((ExtensionAware) this).getExtensions().create("tools", ToolsExtension.class, project);
+    deploy =
+        ((ExtensionAware) this).getExtensions().create("deploy", DeployExtension.class, project);
+    stage =
+        ((ExtensionAware) this)
+            .getExtensions()
+            .create("stage", StageFlexibleExtension.class, project);
+  }
+
+  public void tools(Action<? super ToolsExtension> action) {
+    action.execute(tools);
+  }
+
+  public void deploy(Action<? super DeployExtension> action) {
+    action.execute(deploy);
+  }
+
+  public void stage(Action<? super StageFlexibleExtension> action) {
+    action.execute(stage);
+  }
+
+  @Override
+  public ToolsExtension getTools() {
+    return tools;
+  }
+
+  @Override
+  public DeployExtension getDeploy() {
+    return deploy;
+  }
+
+  public StageFlexibleExtension getStage() {
+    return stage;
+  }
+}
diff --git a/src/main/java/com/google/cloud/tools/gradle/appengine/flexible/AppEngineFlexiblePlugin.java b/src/main/java/com/google/cloud/tools/gradle/appengine/flexible/AppEngineFlexiblePlugin.java
index 4dcd22e2..8b7c138f 100644
--- a/src/main/java/com/google/cloud/tools/gradle/appengine/flexible/AppEngineFlexiblePlugin.java
+++ b/src/main/java/com/google/cloud/tools/gradle/appengine/flexible/AppEngineFlexiblePlugin.java
@@ -17,16 +17,14 @@
 
 package com.google.cloud.tools.gradle.appengine.flexible;
 
-import com.google.cloud.tools.gradle.appengine.core.AppEngineCorePlugin;
+import com.google.cloud.tools.gradle.appengine.core.AppEngineCorePluginConfiguration;
 import com.google.cloud.tools.gradle.appengine.core.DeployExtension;
-import com.google.cloud.tools.gradle.appengine.util.ExtensionUtil;
 import java.io.File;
 import org.gradle.api.Action;
 import org.gradle.api.GradleException;
 import org.gradle.api.Plugin;
 import org.gradle.api.Project;
 import org.gradle.api.plugins.BasePlugin;
-import org.gradle.api.plugins.ExtensionAware;
 import org.gradle.api.plugins.JavaPlugin;
 import org.gradle.api.plugins.WarPlugin;
 import org.gradle.api.tasks.bundling.Jar;
@@ -42,27 +40,27 @@ public class AppEngineFlexiblePlugin implements Plugin<Project> {
   public static final String STAGE_EXTENSION = "stage";
 
   private Project project;
+  private AppEngineFlexibleExtension appengineExtension;
   private StageFlexibleExtension stageExtension;
 
   @Override
   public void apply(Project project) {
     this.project = project;
-    project.getPluginManager().apply(AppEngineCorePlugin.class);
+    appengineExtension =
+        project.getExtensions().create("appengine", AppEngineFlexibleExtension.class);
+    appengineExtension.createSubExtensions(project);
+
+    new AppEngineCorePluginConfiguration()
+        .configureCoreProperties(project, appengineExtension, APP_ENGINE_FLEXIBLE_TASK_GROUP);
 
     configureExtensions();
     createStageTask();
-
-    AppEngineCorePlugin.overrideCoreTasksGroup(project, APP_ENGINE_FLEXIBLE_TASK_GROUP);
   }
 
   private void configureExtensions() {
-    // obtain extensions defined by core plugin.
-    ExtensionAware appengine =
-        new ExtensionUtil(project).get(AppEngineCorePlugin.APPENGINE_EXTENSION);
 
     // create the flexible stage extension and set defaults.
-    stageExtension =
-        appengine.getExtensions().create(STAGE_EXTENSION, StageFlexibleExtension.class, project);
+    stageExtension = appengineExtension.getStage();
     File defaultStagedAppDir = new File(project.getBuildDir(), STAGED_APP_DIR_NAME);
     stageExtension.setStagingDirectory(defaultStagedAppDir);
     stageExtension.setAppEngineDirectory(new File(project.getProjectDir(), "src/main/appengine"));
@@ -73,7 +71,7 @@ private void configureExtensions() {
     }
 
     // obtain deploy extension set defaults
-    DeployExtension deploy = new ExtensionUtil(appengine).get(AppEngineCorePlugin.DEPLOY_EXTENSION);
+    DeployExtension deploy = appengineExtension.getDeploy();
     deploy.setDeployables(new File(defaultStagedAppDir, "app.yaml"));
     // grab default project configuration from staging default
     deploy.setAppEngineDirectory(stageExtension.getAppEngineDirectory());
@@ -122,6 +120,9 @@ public void execute(Project project) {
                         });
                   }
                 });
-    project.getTasks().getByName(AppEngineCorePlugin.DEPLOY_TASK_NAME).dependsOn(stageTask);
+    project
+        .getTasks()
+        .getByName(AppEngineCorePluginConfiguration.DEPLOY_TASK_NAME)
+        .dependsOn(stageTask);
   }
 }
diff --git a/src/main/java/com/google/cloud/tools/gradle/appengine/sourcecontext/SourceContextPlugin.java b/src/main/java/com/google/cloud/tools/gradle/appengine/sourcecontext/SourceContextPlugin.java
index 1aedfaa7..23cdd0f2 100644
--- a/src/main/java/com/google/cloud/tools/gradle/appengine/sourcecontext/SourceContextPlugin.java
+++ b/src/main/java/com/google/cloud/tools/gradle/appengine/sourcecontext/SourceContextPlugin.java
@@ -17,7 +17,7 @@
 
 package com.google.cloud.tools.gradle.appengine.sourcecontext;
 
-import com.google.cloud.tools.gradle.appengine.core.AppEngineCorePlugin;
+import com.google.cloud.tools.gradle.appengine.core.AppEngineCoreExtensionProperties;
 import com.google.cloud.tools.gradle.appengine.core.CloudSdkBuilderFactory;
 import com.google.cloud.tools.gradle.appengine.core.ToolsExtension;
 import com.google.cloud.tools.gradle.appengine.util.ExtensionUtil;
@@ -50,10 +50,8 @@ public void apply(Project project) {
 
   private void createExtension() {
     // obtain extensions defined by core plugin.
-    ExtensionAware appengine =
-        new ExtensionUtil(project).get(AppEngineCorePlugin.APPENGINE_EXTENSION);
-    final ToolsExtension tools =
-        new ExtensionUtil(appengine).get(AppEngineCorePlugin.TOOLS_EXTENSION);
+    ExtensionAware appengine = new ExtensionUtil(project).get("appengine");
+    final ToolsExtension tools = ((AppEngineCoreExtensionProperties) appengine).getTools();
 
     // create source context extension and set defaults
     extension =
diff --git a/src/main/java/com/google/cloud/tools/gradle/appengine/standard/AppEngineStandardExtension.java b/src/main/java/com/google/cloud/tools/gradle/appengine/standard/AppEngineStandardExtension.java
new file mode 100644
index 00000000..3dfb7c92
--- /dev/null
+++ b/src/main/java/com/google/cloud/tools/gradle/appengine/standard/AppEngineStandardExtension.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2018 Google Inc. All Right Reserved.
+ *
+ * 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.google.cloud.tools.gradle.appengine.standard;
+
+import com.google.cloud.tools.gradle.appengine.core.AppEngineCoreExtensionProperties;
+import com.google.cloud.tools.gradle.appengine.core.DeployExtension;
+import com.google.cloud.tools.gradle.appengine.core.ToolsExtension;
+import javax.inject.Inject;
+import org.gradle.api.Action;
+import org.gradle.api.Project;
+import org.gradle.api.plugins.ExtensionAware;
+import org.gradle.internal.impldep.aQute.bnd.build.Run;
+
+public class AppEngineStandardExtension implements AppEngineCoreExtensionProperties {
+  private ToolsExtension tools;
+  private DeployExtension deploy;
+  private StageStandardExtension stage;
+  private RunExtension run;
+
+  /**
+   * Create nested configuration blocks as Extensions. Gradle 4.5 has an ObjectFactory class to
+   * deal with this, transition to that when upgrading gradle version.
+   */
+  public void createSubExtensions(Project project) {
+    tools = ((ExtensionAware) this).getExtensions().create("tools", ToolsExtension.class, project);
+    deploy =
+        ((ExtensionAware) this).getExtensions().create("deploy", DeployExtension.class, project);
+    stage =
+        ((ExtensionAware) this)
+            .getExtensions()
+            .create("stage", StageStandardExtension.class, project);
+    run = ((ExtensionAware) this).getExtensions().create("run", RunExtension.class, project);
+  }
+
+  public void tools(Action<? super ToolsExtension> action) {
+    action.execute(tools);
+  }
+
+  public void deploy(Action<? super DeployExtension> action) {
+    action.execute(deploy);
+  }
+
+  public void stage(Action<? super StageStandardExtension> action) {
+    action.execute(stage);
+  }
+
+  public void run(Action<? super RunExtension> action) {
+    action.execute(run);
+  }
+
+  @Override
+  public ToolsExtension getTools() {
+    return tools;
+  }
+
+  @Override
+  public DeployExtension getDeploy() {
+    return deploy;
+  }
+
+  public StageStandardExtension getStage() {
+    return stage;
+  }
+
+  public RunExtension getRun() {
+    return run;
+  }
+}
diff --git a/src/main/java/com/google/cloud/tools/gradle/appengine/standard/AppEngineStandardPlugin.java b/src/main/java/com/google/cloud/tools/gradle/appengine/standard/AppEngineStandardPlugin.java
index ac476930..bad90cfa 100644
--- a/src/main/java/com/google/cloud/tools/gradle/appengine/standard/AppEngineStandardPlugin.java
+++ b/src/main/java/com/google/cloud/tools/gradle/appengine/standard/AppEngineStandardPlugin.java
@@ -17,17 +17,15 @@
 
 package com.google.cloud.tools.gradle.appengine.standard;
 
-import com.google.cloud.tools.gradle.appengine.core.AppEngineCorePlugin;
+import com.google.cloud.tools.gradle.appengine.core.AppEngineCorePluginConfiguration;
 import com.google.cloud.tools.gradle.appengine.core.CloudSdkBuilderFactory;
 import com.google.cloud.tools.gradle.appengine.core.DeployExtension;
 import com.google.cloud.tools.gradle.appengine.core.ToolsExtension;
-import com.google.cloud.tools.gradle.appengine.util.ExtensionUtil;
 import java.io.File;
 import org.gradle.api.Action;
 import org.gradle.api.Plugin;
 import org.gradle.api.Project;
 import org.gradle.api.plugins.BasePlugin;
-import org.gradle.api.plugins.ExtensionAware;
 import org.gradle.api.plugins.WarPlugin;
 import org.gradle.api.tasks.bundling.War;
 
@@ -49,6 +47,7 @@ public class AppEngineStandardPlugin implements Plugin<Project> {
 
   private Project project;
   private CloudSdkBuilderFactory cloudSdkBuilderFactory;
+  private AppEngineStandardExtension appengineExtension;
   private RunExtension runExtension;
   private StageStandardExtension stageExtension;
   private File explodedWarDir;
@@ -56,7 +55,12 @@ public class AppEngineStandardPlugin implements Plugin<Project> {
   @Override
   public void apply(Project project) {
     this.project = project;
-    project.getPluginManager().apply(AppEngineCorePlugin.class);
+    appengineExtension =
+        project.getExtensions().create("appengine", AppEngineStandardExtension.class);
+    appengineExtension.createSubExtensions(project);
+
+    new AppEngineCorePluginConfiguration()
+        .configureCoreProperties(project, appengineExtension, APP_ENGINE_STANDARD_TASK_GROUP);
 
     explodedWarDir = new File(project.getBuildDir(), "exploded-" + project.getName());
 
@@ -65,36 +69,29 @@ public void apply(Project project) {
     createExplodedWarTask();
     createStageTask();
     createRunTasks();
-
-    AppEngineCorePlugin.overrideCoreTasksGroup(project, APP_ENGINE_STANDARD_TASK_GROUP);
   }
 
   private void configureExtensions() {
-    // obtain extensions defined by core plugin.
-    ExtensionAware appengine =
-        new ExtensionUtil(project).get(AppEngineCorePlugin.APPENGINE_EXTENSION);
 
     // create the run extension and set defaults.
-    runExtension = appengine.getExtensions().create(RUN_EXTENSION, RunExtension.class, project);
+    runExtension = appengineExtension.getRun();
     runExtension.setStartSuccessTimeout(20);
     runExtension.setServices(explodedWarDir);
     runExtension.setServerVersion("1");
 
     // create the stage extension and set defaults.
-    stageExtension =
-        appengine.getExtensions().create(STAGE_EXTENSION, StageStandardExtension.class, project);
+    stageExtension = appengineExtension.getStage();
     File defaultStagedAppDir = new File(project.getBuildDir(), STAGED_APP_DIR_NAME);
     stageExtension.setSourceDirectory(explodedWarDir);
     stageExtension.setStagingDirectory(defaultStagedAppDir);
 
     // obtain deploy extension and set defaults
-    DeployExtension deploy = new ExtensionUtil(appengine).get(AppEngineCorePlugin.DEPLOY_EXTENSION);
+    DeployExtension deploy = appengineExtension.getDeploy();
     deploy.setDeployables(new File(defaultStagedAppDir, "app.yaml"));
     deploy.setAppEngineDirectory(new File(defaultStagedAppDir, "WEB-INF/appengine-generated"));
 
     // tools extension required to initialize cloudSdkBuilderFactory
-    final ToolsExtension tools =
-        new ExtensionUtil(appengine).get(AppEngineCorePlugin.TOOLS_EXTENSION);
+    final ToolsExtension tools = appengineExtension.getTools();
     project.afterEvaluate(
         new Action<Project>() {
           @Override
@@ -161,15 +158,30 @@ public void execute(Project project) {
                 });
 
     // All deployment tasks depend on the stage task.
-    project.getTasks().getByName(AppEngineCorePlugin.DEPLOY_TASK_NAME).dependsOn(stageTask);
-    project.getTasks().getByName(AppEngineCorePlugin.DEPLOY_CRON_TASK_NAME).dependsOn(stageTask);
     project
         .getTasks()
-        .getByName(AppEngineCorePlugin.DEPLOY_DISPATCH_TASK_NAME)
+        .getByName(AppEngineCorePluginConfiguration.DEPLOY_TASK_NAME)
+        .dependsOn(stageTask);
+    project
+        .getTasks()
+        .getByName(AppEngineCorePluginConfiguration.DEPLOY_CRON_TASK_NAME)
+        .dependsOn(stageTask);
+    project
+        .getTasks()
+        .getByName(AppEngineCorePluginConfiguration.DEPLOY_DISPATCH_TASK_NAME)
+        .dependsOn(stageTask);
+    project
+        .getTasks()
+        .getByName(AppEngineCorePluginConfiguration.DEPLOY_DOS_TASK_NAME)
+        .dependsOn(stageTask);
+    project
+        .getTasks()
+        .getByName(AppEngineCorePluginConfiguration.DEPLOY_INDEX_TASK_NAME)
+        .dependsOn(stageTask);
+    project
+        .getTasks()
+        .getByName(AppEngineCorePluginConfiguration.DEPLOY_QUEUE_TASK_NAME)
         .dependsOn(stageTask);
-    project.getTasks().getByName(AppEngineCorePlugin.DEPLOY_DOS_TASK_NAME).dependsOn(stageTask);
-    project.getTasks().getByName(AppEngineCorePlugin.DEPLOY_INDEX_TASK_NAME).dependsOn(stageTask);
-    project.getTasks().getByName(AppEngineCorePlugin.DEPLOY_QUEUE_TASK_NAME).dependsOn(stageTask);
   }
 
   private void createRunTasks() {
diff --git a/src/main/java/com/google/cloud/tools/gradle/appengine/standard/RunExtension.java b/src/main/java/com/google/cloud/tools/gradle/appengine/standard/RunExtension.java
index 6b7f5b71..18297787 100644
--- a/src/main/java/com/google/cloud/tools/gradle/appengine/standard/RunExtension.java
+++ b/src/main/java/com/google/cloud/tools/gradle/appengine/standard/RunExtension.java
@@ -23,6 +23,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import javax.inject.Inject;
 import org.gradle.api.Project;
 import org.gradle.api.ProjectConfigurationException;
 
@@ -65,6 +66,7 @@ public class RunExtension implements RunConfiguration {
    *
    * @param project The gradle project.
    */
+  @Inject
   public RunExtension(Project project) {
     this.project = project;
   }
diff --git a/src/main/java/com/google/cloud/tools/gradle/appengine/standard/StageStandardExtension.java b/src/main/java/com/google/cloud/tools/gradle/appengine/standard/StageStandardExtension.java
index ffb59d36..924deb9c 100644
--- a/src/main/java/com/google/cloud/tools/gradle/appengine/standard/StageStandardExtension.java
+++ b/src/main/java/com/google/cloud/tools/gradle/appengine/standard/StageStandardExtension.java
@@ -19,6 +19,7 @@
 
 import com.google.cloud.tools.appengine.api.deploy.StageStandardConfiguration;
 import java.io.File;
+import javax.inject.Inject;
 import org.gradle.api.Project;
 import org.gradle.api.tasks.Input;
 import org.gradle.api.tasks.InputDirectory;
@@ -44,6 +45,7 @@ public class StageStandardExtension implements StageStandardConfiguration {
   private String runtime;
 
   /** Constuctor. */
+  @Inject
   public StageStandardExtension(Project project) {
     this.project = project;
   }
diff --git a/src/test/java/com/google/cloud/tools/gradle/appengine/AppEnginePluginTest.java b/src/test/java/com/google/cloud/tools/gradle/appengine/AppEnginePluginTest.java
index d342c900..9b1b9de8 100644
--- a/src/test/java/com/google/cloud/tools/gradle/appengine/AppEnginePluginTest.java
+++ b/src/test/java/com/google/cloud/tools/gradle/appengine/AppEnginePluginTest.java
@@ -23,7 +23,7 @@
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 
-import com.google.cloud.tools.gradle.appengine.core.AppEngineCorePlugin;
+import com.google.cloud.tools.gradle.appengine.core.AppEngineCorePluginConfiguration;
 import com.google.cloud.tools.gradle.appengine.flexible.AppEngineFlexiblePlugin;
 import com.google.cloud.tools.gradle.appengine.standard.AppEngineStandardPlugin;
 import java.io.IOException;
@@ -42,7 +42,8 @@ public class AppEnginePluginTest {
   @Test
   public void testCheckGradleVersion_pass() {
     new TestProject(testProjectRoot.getRoot())
-        .applyGradleRunnerWithGradleVersion(AppEngineCorePlugin.GRADLE_MIN_VERSION.getVersion());
+        .applyGradleRunnerWithGradleVersion(
+            AppEngineCorePluginConfiguration.GRADLE_MIN_VERSION.getVersion());
     // pass
   }
 
@@ -57,7 +58,7 @@ public void testCheckGradleVersion_fail() throws IOException {
           ex.getMessage(),
           containsString(
               "Detected Gradle 2.8, but the appengine-gradle-plugin requires "
-                  + AppEngineCorePlugin.GRADLE_MIN_VERSION
+                  + AppEngineCorePluginConfiguration.GRADLE_MIN_VERSION
                   + " or higher."));
     }
   }
diff --git a/src/test/java/com/google/cloud/tools/gradle/appengine/flexible/AppEngineFlexiblePluginTest.java b/src/test/java/com/google/cloud/tools/gradle/appengine/flexible/AppEngineFlexiblePluginTest.java
index 02f017ea..7581dd05 100644
--- a/src/test/java/com/google/cloud/tools/gradle/appengine/flexible/AppEngineFlexiblePluginTest.java
+++ b/src/test/java/com/google/cloud/tools/gradle/appengine/flexible/AppEngineFlexiblePluginTest.java
@@ -25,9 +25,8 @@
 
 import com.google.cloud.tools.gradle.appengine.BuildResultFilter;
 import com.google.cloud.tools.gradle.appengine.TestProject;
-import com.google.cloud.tools.gradle.appengine.core.AppEngineCorePlugin;
+import com.google.cloud.tools.gradle.appengine.core.AppEngineCorePluginConfiguration;
 import com.google.cloud.tools.gradle.appengine.core.DeployExtension;
-import com.google.cloud.tools.gradle.appengine.util.ExtensionUtil;
 import com.google.common.collect.ImmutableList;
 import java.io.File;
 import java.io.IOException;
@@ -36,7 +35,6 @@
 import org.gradle.api.Action;
 import org.gradle.api.Project;
 import org.gradle.api.Task;
-import org.gradle.api.plugins.ExtensionAware;
 import org.gradle.api.specs.Spec;
 import org.gradle.api.tasks.bundling.Jar;
 import org.gradle.api.tasks.bundling.War;
@@ -58,7 +56,8 @@ private TestProject createTestProject() throws IOException {
   @Test
   public void testCheckGradleVersion_pass() throws IOException {
     createTestProject()
-        .applyGradleRunnerWithGradleVersion(AppEngineCorePlugin.GRADLE_MIN_VERSION.getVersion());
+        .applyGradleRunnerWithGradleVersion(
+            AppEngineCorePluginConfiguration.GRADLE_MIN_VERSION.getVersion());
     // pass
   }
 
@@ -71,7 +70,7 @@ public void testCheckGradleVersion_fail() throws IOException {
           ex.getMessage(),
           containsString(
               "Detected Gradle 2.8, but the appengine-gradle-plugin requires "
-                  + AppEngineCorePlugin.GRADLE_MIN_VERSION
+                  + AppEngineCorePluginConfiguration.GRADLE_MIN_VERSION
                   + " or higher."));
     }
   }
@@ -141,9 +140,9 @@ public void testDeployQueue_taskTree() throws IOException {
   public void testDefaultConfiguration() throws IOException {
     Project p = new TestProject(testProjectDir.getRoot()).applyFlexibleWarProjectBuilder();
 
-    ExtensionAware ext = (ExtensionAware) p.getExtensions().getByName("appengine");
-    DeployExtension deployExt = new ExtensionUtil(ext).get("deploy");
-    StageFlexibleExtension stageExt = new ExtensionUtil(ext).get("stage");
+    AppEngineFlexibleExtension ext = p.getExtensions().getByType(AppEngineFlexibleExtension.class);
+    DeployExtension deployExt = ext.getDeploy();
+    StageFlexibleExtension stageExt = ext.getStage();
 
     assertEquals(new File(p.getBuildDir(), "staged-app"), stageExt.getStagingDirectory());
     assertEquals(
@@ -164,10 +163,8 @@ public void testDefaultConfigurationAlternative() throws IOException {
     Project p =
         new TestProject(testProjectDir.getRoot()).addDockerDir().applyFlexibleProjectBuilder();
 
-    ExtensionAware ext =
-        (ExtensionAware) p.getExtensions().getByName(AppEngineCorePlugin.APPENGINE_EXTENSION);
-    StageFlexibleExtension stageExt =
-        new ExtensionUtil(ext).get(AppEngineFlexiblePlugin.STAGE_EXTENSION);
+    AppEngineFlexibleExtension ext = p.getExtensions().getByType(AppEngineFlexibleExtension.class);
+    StageFlexibleExtension stageExt = ext.getStage();
 
     assertTrue(new File(testProjectDir.getRoot(), "src/main/docker").exists());
     assertEquals((((Jar) p.getProperties().get("jar")).getArchivePath()), stageExt.getArtifact());
diff --git a/src/test/java/com/google/cloud/tools/gradle/appengine/sourcecontext/SourceContextPluginTest.java b/src/test/java/com/google/cloud/tools/gradle/appengine/sourcecontext/SourceContextPluginTest.java
index b20d74b6..274434d1 100644
--- a/src/test/java/com/google/cloud/tools/gradle/appengine/sourcecontext/SourceContextPluginTest.java
+++ b/src/test/java/com/google/cloud/tools/gradle/appengine/sourcecontext/SourceContextPluginTest.java
@@ -18,7 +18,7 @@
 package com.google.cloud.tools.gradle.appengine.sourcecontext;
 
 import com.google.cloud.tools.gradle.appengine.BuildResultFilter;
-import com.google.cloud.tools.gradle.appengine.core.AppEngineCorePlugin;
+import com.google.cloud.tools.gradle.appengine.core.AppEngineCorePluginConfiguration;
 import com.google.cloud.tools.gradle.appengine.standard.AppEngineStandardPlugin;
 import com.google.cloud.tools.gradle.appengine.util.ExtensionUtil;
 import com.google.common.base.Charsets;
@@ -102,7 +102,8 @@ public void testDefaultConfiguration() throws IOException {
     ((ProjectInternal) project).evaluate();
 
     ExtensionAware ext =
-        (ExtensionAware) project.getExtensions().getByName(AppEngineCorePlugin.APPENGINE_EXTENSION);
+        (ExtensionAware)
+            project.getExtensions().getByName(AppEngineCorePluginConfiguration.APPENGINE_EXTENSION);
     GenRepoInfoFileExtension genRepoInfoExt =
         new ExtensionUtil(ext).get(SourceContextPlugin.SOURCE_CONTEXT_EXTENSION);
     Assert.assertEquals(
diff --git a/src/test/java/com/google/cloud/tools/gradle/appengine/standard/AppEngineStandardExtensionTest.java b/src/test/java/com/google/cloud/tools/gradle/appengine/standard/AppEngineStandardExtensionTest.java
index db131a84..c9864f01 100644
--- a/src/test/java/com/google/cloud/tools/gradle/appengine/standard/AppEngineStandardExtensionTest.java
+++ b/src/test/java/com/google/cloud/tools/gradle/appengine/standard/AppEngineStandardExtensionTest.java
@@ -17,10 +17,8 @@
 
 package com.google.cloud.tools.gradle.appengine.standard;
 
-import com.google.cloud.tools.gradle.appengine.core.AppEngineCorePlugin;
 import com.google.cloud.tools.gradle.appengine.core.DeployExtension;
 import com.google.cloud.tools.gradle.appengine.core.ToolsExtension;
-import com.google.cloud.tools.gradle.appengine.util.ExtensionUtil;
 import com.google.common.base.Charsets;
 import com.google.common.collect.ImmutableMap;
 import java.io.File;
@@ -30,7 +28,6 @@
 import java.nio.file.Path;
 import org.gradle.api.Project;
 import org.gradle.api.internal.project.ProjectInternal;
-import org.gradle.api.plugins.ExtensionAware;
 import org.gradle.api.plugins.JavaPlugin;
 import org.gradle.api.plugins.WarPlugin;
 import org.gradle.internal.impldep.org.testng.Assert;
@@ -72,9 +69,8 @@ private Project setUpTestProject(String buildFileName) throws IOException {
   public void testReadEnvironment() throws IOException {
     Project p = setUpTestProject("environment-params");
 
-    ExtensionAware ext =
-        (ExtensionAware) p.getExtensions().getByName(AppEngineCorePlugin.APPENGINE_EXTENSION);
-    RunExtension run = new ExtensionUtil(ext).get(AppEngineStandardPlugin.RUN_EXTENSION);
+    AppEngineStandardExtension ext = p.getExtensions().getByType(AppEngineStandardExtension.class);
+    RunExtension run = ext.getRun();
 
     Assert.assertEquals(run.getEnvironment(), ImmutableMap.of("key1", "value1", "key2", "value2"));
   }
@@ -83,13 +79,11 @@ public void testReadEnvironment() throws IOException {
   public void testFileAsString() throws IOException {
     Project p = setUpTestProject("file-as-string");
 
-    ExtensionAware ext =
-        (ExtensionAware) p.getExtensions().getByName(AppEngineCorePlugin.APPENGINE_EXTENSION);
-    DeployExtension deploy = new ExtensionUtil(ext).get(AppEngineCorePlugin.DEPLOY_EXTENSION);
-    StageStandardExtension stage =
-        new ExtensionUtil(ext).get(AppEngineStandardPlugin.STAGE_EXTENSION);
-    RunExtension run = new ExtensionUtil(ext).get(AppEngineStandardPlugin.RUN_EXTENSION);
-    ToolsExtension tools = new ExtensionUtil(ext).get(AppEngineCorePlugin.TOOLS_EXTENSION);
+    AppEngineStandardExtension ext = p.getExtensions().getByType(AppEngineStandardExtension.class);
+    DeployExtension deploy = ext.getDeploy();
+    StageStandardExtension stage = ext.getStage();
+    RunExtension run = ext.getRun();
+    ToolsExtension tools = ext.getTools();
 
     Assert.assertEquals(deploy.getDeployables().size(), 1);
     Assert.assertEquals("test", deploy.getDeployables().get(0).getName());
@@ -105,10 +99,9 @@ public void testFileAsString() throws IOException {
   public void testFilesAsString() throws IOException {
     Project p = setUpTestProject("files-as-string");
 
-    ExtensionAware ext =
-        (ExtensionAware) p.getExtensions().getByName(AppEngineCorePlugin.APPENGINE_EXTENSION);
-    DeployExtension deploy = new ExtensionUtil(ext).get(AppEngineCorePlugin.DEPLOY_EXTENSION);
-    RunExtension run = new ExtensionUtil(ext).get(AppEngineStandardPlugin.RUN_EXTENSION);
+    AppEngineStandardExtension ext = p.getExtensions().getByType(AppEngineStandardExtension.class);
+    RunExtension run = ext.getRun();
+    DeployExtension deploy = ext.getDeploy();
 
     Assert.assertEquals(deploy.getDeployables().size(), 2);
     Assert.assertEquals("test0", deploy.getDeployables().get(0).getName());
@@ -122,13 +115,11 @@ public void testFilesAsString() throws IOException {
   public void testFileAsFile() throws IOException {
     Project p = setUpTestProject("file-as-file");
 
-    ExtensionAware ext =
-        (ExtensionAware) p.getExtensions().getByName(AppEngineCorePlugin.APPENGINE_EXTENSION);
-    DeployExtension deploy = new ExtensionUtil(ext).get(AppEngineCorePlugin.DEPLOY_EXTENSION);
-    StageStandardExtension stage =
-        new ExtensionUtil(ext).get(AppEngineStandardPlugin.STAGE_EXTENSION);
-    RunExtension run = new ExtensionUtil(ext).get(AppEngineStandardPlugin.RUN_EXTENSION);
-    ToolsExtension tools = new ExtensionUtil(ext).get(AppEngineCorePlugin.TOOLS_EXTENSION);
+    AppEngineStandardExtension ext = p.getExtensions().getByType(AppEngineStandardExtension.class);
+    RunExtension run = ext.getRun();
+    DeployExtension deploy = ext.getDeploy();
+    StageStandardExtension stage = ext.getStage();
+    ToolsExtension tools = ext.getTools();
 
     Assert.assertEquals(deploy.getDeployables().size(), 1);
     Assert.assertEquals("test", deploy.getDeployables().get(0).getName());
@@ -144,10 +135,9 @@ public void testFileAsFile() throws IOException {
   public void testFilesAsFiles() throws IOException {
     Project p = setUpTestProject("files-as-files");
 
-    ExtensionAware ext =
-        (ExtensionAware) p.getExtensions().getByName(AppEngineCorePlugin.APPENGINE_EXTENSION);
-    DeployExtension deploy = new ExtensionUtil(ext).get(AppEngineCorePlugin.DEPLOY_EXTENSION);
-    RunExtension run = new ExtensionUtil(ext).get(AppEngineStandardPlugin.RUN_EXTENSION);
+    AppEngineStandardExtension ext = p.getExtensions().getByType(AppEngineStandardExtension.class);
+    RunExtension run = ext.getRun();
+    DeployExtension deploy = ext.getDeploy();
 
     Assert.assertEquals(deploy.getDeployables().size(), 2);
     Assert.assertEquals("test0", deploy.getDeployables().get(0).getName());
diff --git a/src/test/java/com/google/cloud/tools/gradle/appengine/standard/AppEngineStandardPluginTest.java b/src/test/java/com/google/cloud/tools/gradle/appengine/standard/AppEngineStandardPluginTest.java
index 965411c3..3d5e712a 100644
--- a/src/test/java/com/google/cloud/tools/gradle/appengine/standard/AppEngineStandardPluginTest.java
+++ b/src/test/java/com/google/cloud/tools/gradle/appengine/standard/AppEngineStandardPluginTest.java
@@ -24,9 +24,8 @@
 
 import com.google.cloud.tools.gradle.appengine.BuildResultFilter;
 import com.google.cloud.tools.gradle.appengine.TestProject;
-import com.google.cloud.tools.gradle.appengine.core.AppEngineCorePlugin;
+import com.google.cloud.tools.gradle.appengine.core.AppEngineCorePluginConfiguration;
 import com.google.cloud.tools.gradle.appengine.core.DeployExtension;
-import com.google.cloud.tools.gradle.appengine.util.ExtensionUtil;
 import com.google.common.collect.ImmutableList;
 import java.io.File;
 import java.io.IOException;
@@ -35,7 +34,6 @@
 import org.gradle.api.Action;
 import org.gradle.api.Project;
 import org.gradle.api.Task;
-import org.gradle.api.plugins.ExtensionAware;
 import org.gradle.api.specs.Spec;
 import org.gradle.testkit.runner.BuildResult;
 import org.gradle.testkit.runner.UnexpectedBuildFailure;
@@ -55,7 +53,8 @@ private TestProject createTestProject() throws IOException {
   @Test
   public void testCheckGradleVersion_pass() throws IOException {
     createTestProject()
-        .applyGradleRunnerWithGradleVersion(AppEngineCorePlugin.GRADLE_MIN_VERSION.getVersion());
+        .applyGradleRunnerWithGradleVersion(
+            AppEngineCorePluginConfiguration.GRADLE_MIN_VERSION.getVersion());
     // pass
   }
 
@@ -68,7 +67,7 @@ public void testCheckGradleVersion_fail() throws IOException {
           ex.getMessage(),
           containsString(
               "Detected Gradle 2.8, but the appengine-gradle-plugin requires "
-                  + AppEngineCorePlugin.GRADLE_MIN_VERSION
+                  + AppEngineCorePluginConfiguration.GRADLE_MIN_VERSION
                   + " or higher."));
     }
   }
@@ -236,13 +235,10 @@ public void testDefaultConfiguration() throws IOException {
             .addAppEngineWebXml()
             .applyStandardProjectBuilder();
 
-    final ExtensionAware ext =
-        (ExtensionAware) p.getExtensions().getByName(AppEngineCorePlugin.APPENGINE_EXTENSION);
-    final DeployExtension deployExt =
-        new ExtensionUtil(ext).get(AppEngineCorePlugin.DEPLOY_EXTENSION);
-    final StageStandardExtension stageExt =
-        new ExtensionUtil(ext).get(AppEngineStandardPlugin.STAGE_EXTENSION);
-    final RunExtension run = new ExtensionUtil(ext).get(AppEngineStandardPlugin.RUN_EXTENSION);
+    AppEngineStandardExtension ext = p.getExtensions().getByType(AppEngineStandardExtension.class);
+    final RunExtension run = ext.getRun();
+    final DeployExtension deployExt = ext.getDeploy();
+    final StageStandardExtension stageExt = ext.getStage();
 
     assertEquals(
         new File(p.getBuildDir(), "exploded-" + p.getName()), stageExt.getSourceDirectory());

From 24b303d60923c4471174da486462c1fd080cec74 Mon Sep 17 00:00:00 2001
From: Appu Goundan <appu@google.com>
Date: Thu, 1 Feb 2018 18:44:07 -0500
Subject: [PATCH 2/4] formatting

---
 .../appengine/flexible/AppEngineFlexibleExtension.java      | 4 +---
 .../appengine/standard/AppEngineStandardExtension.java      | 6 ++----
 2 files changed, 3 insertions(+), 7 deletions(-)

diff --git a/src/main/java/com/google/cloud/tools/gradle/appengine/flexible/AppEngineFlexibleExtension.java b/src/main/java/com/google/cloud/tools/gradle/appengine/flexible/AppEngineFlexibleExtension.java
index 2ba11a33..35c9ec2e 100644
--- a/src/main/java/com/google/cloud/tools/gradle/appengine/flexible/AppEngineFlexibleExtension.java
+++ b/src/main/java/com/google/cloud/tools/gradle/appengine/flexible/AppEngineFlexibleExtension.java
@@ -29,9 +29,7 @@ public class AppEngineFlexibleExtension implements AppEngineCoreExtensionPropert
   private DeployExtension deploy;
   private StageFlexibleExtension stage;
 
-  /**
-   * Create nested configuration blocks as Extensions.
-   */
+  /** Create nested configuration blocks as Extensions. */
   public void createSubExtensions(Project project) {
     tools = ((ExtensionAware) this).getExtensions().create("tools", ToolsExtension.class, project);
     deploy =
diff --git a/src/main/java/com/google/cloud/tools/gradle/appengine/standard/AppEngineStandardExtension.java b/src/main/java/com/google/cloud/tools/gradle/appengine/standard/AppEngineStandardExtension.java
index 3dfb7c92..af5b3984 100644
--- a/src/main/java/com/google/cloud/tools/gradle/appengine/standard/AppEngineStandardExtension.java
+++ b/src/main/java/com/google/cloud/tools/gradle/appengine/standard/AppEngineStandardExtension.java
@@ -20,11 +20,9 @@
 import com.google.cloud.tools.gradle.appengine.core.AppEngineCoreExtensionProperties;
 import com.google.cloud.tools.gradle.appengine.core.DeployExtension;
 import com.google.cloud.tools.gradle.appengine.core.ToolsExtension;
-import javax.inject.Inject;
 import org.gradle.api.Action;
 import org.gradle.api.Project;
 import org.gradle.api.plugins.ExtensionAware;
-import org.gradle.internal.impldep.aQute.bnd.build.Run;
 
 public class AppEngineStandardExtension implements AppEngineCoreExtensionProperties {
   private ToolsExtension tools;
@@ -33,8 +31,8 @@ public class AppEngineStandardExtension implements AppEngineCoreExtensionPropert
   private RunExtension run;
 
   /**
-   * Create nested configuration blocks as Extensions. Gradle 4.5 has an ObjectFactory class to
-   * deal with this, transition to that when upgrading gradle version.
+   * Create nested configuration blocks as Extensions. Gradle 4.5 has an ObjectFactory class to deal
+   * with this, transition to that when upgrading gradle version.
    */
   public void createSubExtensions(Project project) {
     tools = ((ExtensionAware) this).getExtensions().create("tools", ToolsExtension.class, project);

From e47649846bf7f81c67a20dddfb1b8e7da6917560 Mon Sep 17 00:00:00 2001
From: Appu Goundan <appu@google.com>
Date: Fri, 2 Feb 2018 16:57:49 -0500
Subject: [PATCH 3/4] remove unecessary file

---
 .../appengine/core/AppEngineExtension.java    | 23 -------------------
 1 file changed, 23 deletions(-)
 delete mode 100644 src/main/java/com/google/cloud/tools/gradle/appengine/core/AppEngineExtension.java

diff --git a/src/main/java/com/google/cloud/tools/gradle/appengine/core/AppEngineExtension.java b/src/main/java/com/google/cloud/tools/gradle/appengine/core/AppEngineExtension.java
deleted file mode 100644
index e53eecb4..00000000
--- a/src/main/java/com/google/cloud/tools/gradle/appengine/core/AppEngineExtension.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (c) 2016 Google Inc. All Right Reserved.
- *
- * 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.google.cloud.tools.gradle.appengine.core;
-
-/** Base Extension class for all our appengine extensions to include themselves into. */
-public class AppEngineExtension {
-  // dynamically fill this in in AppEngineCorePlugin
-}

From eae69dc40d7f769b4ea74dc399993fb91ab81629 Mon Sep 17 00:00:00 2001
From: Appu Goundan <appu@google.com>
Date: Thu, 8 Feb 2018 17:32:18 -0500
Subject: [PATCH 4/4] Fixes

---
 .../AppEngineCorePluginConfiguration.java     |  3 ---
 .../appengine/core/DeployExtension.java       |  2 --
 .../gradle/appengine/core/ToolsExtension.java |  2 --
 .../flexible/AppEngineFlexibleExtension.java  | 11 ++++++++---
 .../flexible/AppEngineFlexiblePlugin.java     |  1 -
 .../standard/AppEngineStandardExtension.java  | 19 +++++++++++--------
 .../appengine/standard/RunExtension.java      |  2 --
 .../standard/StageStandardExtension.java      |  2 --
 8 files changed, 19 insertions(+), 23 deletions(-)

diff --git a/src/main/java/com/google/cloud/tools/gradle/appengine/core/AppEngineCorePluginConfiguration.java b/src/main/java/com/google/cloud/tools/gradle/appengine/core/AppEngineCorePluginConfiguration.java
index 28582816..b4c84e03 100644
--- a/src/main/java/com/google/cloud/tools/gradle/appengine/core/AppEngineCorePluginConfiguration.java
+++ b/src/main/java/com/google/cloud/tools/gradle/appengine/core/AppEngineCorePluginConfiguration.java
@@ -30,9 +30,6 @@ public class AppEngineCorePluginConfiguration {
 
   public static final GradleVersion GRADLE_MIN_VERSION = GradleVersion.version("3.4.1");
 
-  // this is just a placeholder to be replaced by the standard/flex group
-  public static final String APP_ENGINE_TASK_GROUP = "App Engine core tasks";
-
   public static final String DEPLOY_TASK_NAME = "appengineDeploy";
   public static final String DEPLOY_CRON_TASK_NAME = "appengineDeployCron";
   public static final String DEPLOY_DISPATCH_TASK_NAME = "appengineDeployDispatch";
diff --git a/src/main/java/com/google/cloud/tools/gradle/appengine/core/DeployExtension.java b/src/main/java/com/google/cloud/tools/gradle/appengine/core/DeployExtension.java
index 3304cebb..5d6bd9b8 100644
--- a/src/main/java/com/google/cloud/tools/gradle/appengine/core/DeployExtension.java
+++ b/src/main/java/com/google/cloud/tools/gradle/appengine/core/DeployExtension.java
@@ -22,7 +22,6 @@
 import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
-import javax.inject.Inject;
 import org.gradle.api.Project;
 
 /** Extension element to define Deployable configurations for App Engine. */
@@ -42,7 +41,6 @@ public class DeployExtension
   private String version;
   private File appEngineDirectory;
 
-  @Inject
   public DeployExtension(Project gradleProject) {
     this.gradleProject = gradleProject;
   }
diff --git a/src/main/java/com/google/cloud/tools/gradle/appengine/core/ToolsExtension.java b/src/main/java/com/google/cloud/tools/gradle/appengine/core/ToolsExtension.java
index 808959f7..bd0852bd 100644
--- a/src/main/java/com/google/cloud/tools/gradle/appengine/core/ToolsExtension.java
+++ b/src/main/java/com/google/cloud/tools/gradle/appengine/core/ToolsExtension.java
@@ -18,7 +18,6 @@
 package com.google.cloud.tools.gradle.appengine.core;
 
 import java.io.File;
-import javax.inject.Inject;
 import org.gradle.api.Project;
 
 /** Extension element to define the location of cloud sdk tooling. */
@@ -28,7 +27,6 @@ public class ToolsExtension {
 
   private File cloudSdkHome;
 
-  @Inject
   public ToolsExtension(Project project) {
     this.project = project;
   }
diff --git a/src/main/java/com/google/cloud/tools/gradle/appengine/flexible/AppEngineFlexibleExtension.java b/src/main/java/com/google/cloud/tools/gradle/appengine/flexible/AppEngineFlexibleExtension.java
index 35c9ec2e..37a19ef3 100644
--- a/src/main/java/com/google/cloud/tools/gradle/appengine/flexible/AppEngineFlexibleExtension.java
+++ b/src/main/java/com/google/cloud/tools/gradle/appengine/flexible/AppEngineFlexibleExtension.java
@@ -25,19 +25,24 @@
 import org.gradle.api.plugins.ExtensionAware;
 
 public class AppEngineFlexibleExtension implements AppEngineCoreExtensionProperties {
+  private static final String TOOLS_EXT = "tools";
+  private static final String DEPLOY_EXT = "deploy";
+  private static final String STAGE_EXT = "stage";
+
   private ToolsExtension tools;
   private DeployExtension deploy;
   private StageFlexibleExtension stage;
 
   /** Create nested configuration blocks as Extensions. */
   public void createSubExtensions(Project project) {
-    tools = ((ExtensionAware) this).getExtensions().create("tools", ToolsExtension.class, project);
+    tools =
+        ((ExtensionAware) this).getExtensions().create(TOOLS_EXT, ToolsExtension.class, project);
     deploy =
-        ((ExtensionAware) this).getExtensions().create("deploy", DeployExtension.class, project);
+        ((ExtensionAware) this).getExtensions().create(DEPLOY_EXT, DeployExtension.class, project);
     stage =
         ((ExtensionAware) this)
             .getExtensions()
-            .create("stage", StageFlexibleExtension.class, project);
+            .create(STAGE_EXT, StageFlexibleExtension.class, project);
   }
 
   public void tools(Action<? super ToolsExtension> action) {
diff --git a/src/main/java/com/google/cloud/tools/gradle/appengine/flexible/AppEngineFlexiblePlugin.java b/src/main/java/com/google/cloud/tools/gradle/appengine/flexible/AppEngineFlexiblePlugin.java
index 8b7c138f..7db15275 100644
--- a/src/main/java/com/google/cloud/tools/gradle/appengine/flexible/AppEngineFlexiblePlugin.java
+++ b/src/main/java/com/google/cloud/tools/gradle/appengine/flexible/AppEngineFlexiblePlugin.java
@@ -37,7 +37,6 @@ public class AppEngineFlexiblePlugin implements Plugin<Project> {
   private static final String STAGE_TASK_NAME = "appengineStage";
 
   private static final String STAGED_APP_DIR_NAME = "staged-app";
-  public static final String STAGE_EXTENSION = "stage";
 
   private Project project;
   private AppEngineFlexibleExtension appengineExtension;
diff --git a/src/main/java/com/google/cloud/tools/gradle/appengine/standard/AppEngineStandardExtension.java b/src/main/java/com/google/cloud/tools/gradle/appengine/standard/AppEngineStandardExtension.java
index af5b3984..5821cc24 100644
--- a/src/main/java/com/google/cloud/tools/gradle/appengine/standard/AppEngineStandardExtension.java
+++ b/src/main/java/com/google/cloud/tools/gradle/appengine/standard/AppEngineStandardExtension.java
@@ -25,24 +25,27 @@
 import org.gradle.api.plugins.ExtensionAware;
 
 public class AppEngineStandardExtension implements AppEngineCoreExtensionProperties {
+  private static final String TOOLS_EXT = "tools";
+  private static final String DEPLOY_EXT = "deploy";
+  private static final String STAGE_EXT = "stage";
+  private static final String RUN_EXT = "run";
+
   private ToolsExtension tools;
   private DeployExtension deploy;
   private StageStandardExtension stage;
   private RunExtension run;
 
-  /**
-   * Create nested configuration blocks as Extensions. Gradle 4.5 has an ObjectFactory class to deal
-   * with this, transition to that when upgrading gradle version.
-   */
+  /** Create nested configuration blocks as Extensions. */
   public void createSubExtensions(Project project) {
-    tools = ((ExtensionAware) this).getExtensions().create("tools", ToolsExtension.class, project);
+    tools =
+        ((ExtensionAware) this).getExtensions().create(TOOLS_EXT, ToolsExtension.class, project);
     deploy =
-        ((ExtensionAware) this).getExtensions().create("deploy", DeployExtension.class, project);
+        ((ExtensionAware) this).getExtensions().create(DEPLOY_EXT, DeployExtension.class, project);
     stage =
         ((ExtensionAware) this)
             .getExtensions()
-            .create("stage", StageStandardExtension.class, project);
-    run = ((ExtensionAware) this).getExtensions().create("run", RunExtension.class, project);
+            .create(STAGE_EXT, StageStandardExtension.class, project);
+    run = ((ExtensionAware) this).getExtensions().create(RUN_EXT, RunExtension.class, project);
   }
 
   public void tools(Action<? super ToolsExtension> action) {
diff --git a/src/main/java/com/google/cloud/tools/gradle/appengine/standard/RunExtension.java b/src/main/java/com/google/cloud/tools/gradle/appengine/standard/RunExtension.java
index 18297787..6b7f5b71 100644
--- a/src/main/java/com/google/cloud/tools/gradle/appengine/standard/RunExtension.java
+++ b/src/main/java/com/google/cloud/tools/gradle/appengine/standard/RunExtension.java
@@ -23,7 +23,6 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
-import javax.inject.Inject;
 import org.gradle.api.Project;
 import org.gradle.api.ProjectConfigurationException;
 
@@ -66,7 +65,6 @@ public class RunExtension implements RunConfiguration {
    *
    * @param project The gradle project.
    */
-  @Inject
   public RunExtension(Project project) {
     this.project = project;
   }
diff --git a/src/main/java/com/google/cloud/tools/gradle/appengine/standard/StageStandardExtension.java b/src/main/java/com/google/cloud/tools/gradle/appengine/standard/StageStandardExtension.java
index 924deb9c..ffb59d36 100644
--- a/src/main/java/com/google/cloud/tools/gradle/appengine/standard/StageStandardExtension.java
+++ b/src/main/java/com/google/cloud/tools/gradle/appengine/standard/StageStandardExtension.java
@@ -19,7 +19,6 @@
 
 import com.google.cloud.tools.appengine.api.deploy.StageStandardConfiguration;
 import java.io.File;
-import javax.inject.Inject;
 import org.gradle.api.Project;
 import org.gradle.api.tasks.Input;
 import org.gradle.api.tasks.InputDirectory;
@@ -45,7 +44,6 @@ public class StageStandardExtension implements StageStandardConfiguration {
   private String runtime;
 
   /** Constuctor. */
-  @Inject
   public StageStandardExtension(Project project) {
     this.project = project;
   }