SlideShare a Scribd company logo
Weapons for Boilerplate
DESTRUCTION
Tomás Ruiz López
Everyware Technologies
Droidcon Spain 2015@tomasruizlopez
tomas@everywaretech.es
Tomás Ruiz-López
Software Design Manager at Everyware Technologies
@tomasruizlopez
@everywaretech
/everywaretech
http://www.everywaretech.es
WHO AM I?
Postdoctoral Fellow at Cancer Registry of Norway
Everyware Technologies
tomas@everywaretech.es
WHY THIS TALK?
BOILERPLATE!
LAZYNESS
 public	
  class	
  MyParcelable	
  implements	
  Parcelable	
  {	
  
	
  	
  	
  	
  	
  private	
  int	
  mData;	
  
!
	
  	
  	
  	
  	
  public	
  int	
  describeContents()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  0;	
  
	
  	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  	
  public	
  void	
  writeToParcel(Parcel	
  out,	
  int	
  flags)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  out.writeInt(mData);	
  
	
  	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  	
  public	
  static	
  final	
  Parcelable.Creator<MyParcelable>	
  CREATOR	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  =	
  new	
  Parcelable.Creator<MyParcelable>()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  public	
  MyParcelable	
  createFromParcel(Parcel	
  in)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  new	
  MyParcelable(in);	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  	
  public	
  MyParcelable[]	
  newArray(int	
  size)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  new	
  MyParcelable[size];	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  };	
  
	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  private	
  MyParcelable(Parcel	
  in)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  mData	
  =	
  in.readInt();	
  
	
  	
  	
  	
  	
  }	
  
	
  }
CODE COMPLETIONS
Postfix Completion
Type expression
ending in a dot
Ctrl + Space
1
2 Choose:
	
   field,	
  var,	
  cast,	
  instanceof,	
  
	
   not	
  null,	
  null,	
  par,	
  for,	
  fori,	
  
	
   …3
Postfix Completion
var
field
Postfix Completion
var
field
Postfix Completion
var
field
Postfix Completion
fori
for
notnull
Postfix Completion
fori
for
notnull
Postfix Completion
fori
for
notnull
Postfix Completion
fori
for
notnull
Postfix Completion
Quick typing
Short completions
Remember commands
Not customizable
Live Templates
Type your shortcut keyword
Expand with {Space | Tab | Enter}
1
2
Fill missing parts
3
Live Templates
geti
lazy
Live Templates
geti
lazy
Live Templates
geti
lazy
Live Templates
Create Template Group
or Live Template
1
Editable in Preferences	
  >	
  Live	
  Templates
Live Templates
Fill abbreviation, description and
template code
2
Editable in Preferences	
  >	
  Live	
  Templates
Live Templates
Define applicability scope
3
Editable in Preferences	
  >	
  Live	
  Templates
Live Templates
Use it
4
Editable in Preferences	
  >	
  Live	
  Templates
Live Templates
Use it
4
Editable in Preferences	
  >	
  Live	
  Templates
Live Templates
Templates can be parameterized
2b
Editable in Preferences	
  >	
  Live	
  Templates
Live Templates
Templates can be parameterized
2b
Editable in Preferences	
  >	
  Live	
  Templates
Live Templates
Templates can be parameterized
2b
Editable in Preferences	
  >	
  Live	
  Templates
Live Templates
Templates can be parameterized
2b
Editable in Preferences	
  >	
  Live	
  Templates
Live Templates
Quick typing
Short completions
Remember commands
Customizable (to some extent)
ADT TEMPLATES
file0..*
Template Structure
Template Folder
root
globals.xml.ftl1
recipe.xml.ftl1
template.xml1
icon.png0..*
file.ftl0..*
Place it under
!
<AndroidStudioPath>/plugins/android/lib/templates
file0..*
Template Structure
Template Folder
root
globals.xml.ftl1
recipe.xml.ftl1
template.xml1
icon.png0..*
file.ftl0..*
Definition of the
template
Place it under
!
<AndroidStudioPath>/plugins/android/lib/templates
file0..*
Template Structure
Template Folder
root
globals.xml.ftl1
recipe.xml.ftl1
template.xml1
icon.png0..*
file.ftl0..*
Place it under
!
<AndroidStudioPath>/plugins/android/lib/templates
file0..*
Template Structure
Template Folder
root
globals.xml.ftl1
recipe.xml.ftl1
template.xml1
icon.png0..*
file.ftl0..*
Global variables for
the code generation
Place it under
!
<AndroidStudioPath>/plugins/android/lib/templates
file0..*
Template Structure
Template Folder
root
globals.xml.ftl1
recipe.xml.ftl1
template.xml1
icon.png0..*
file.ftl0..*
Place it under
!
<AndroidStudioPath>/plugins/android/lib/templates
file0..*
Template Structure
Template Folder
root
globals.xml.ftl1
recipe.xml.ftl1
template.xml1
icon.png0..*
file.ftl0..*
Actions to perform
when template is
selected
Place it under
!
<AndroidStudioPath>/plugins/android/lib/templates
file0..*
Template Structure
Template Folder
root
globals.xml.ftl1
recipe.xml.ftl1
template.xml1
icon.png0..*
file.ftl0..*
Place it under
!
<AndroidStudioPath>/plugins/android/lib/templates
file0..*
Template Structure
Template Folder
root
globals.xml.ftl1
recipe.xml.ftl1
template.xml1
icon.png0..*
file.ftl0..*Icons to represent
the template
Place it under
!
<AndroidStudioPath>/plugins/android/lib/templates
file0..*
Template Structure
Template Folder
root
globals.xml.ftl1
recipe.xml.ftl1
template.xml1
icon.png0..*
file.ftl0..*
Place it under
!
<AndroidStudioPath>/plugins/android/lib/templates
file0..*
Template Structure
Template Folder
root
globals.xml.ftl1
recipe.xml.ftl1
template.xml1
icon.png0..*
file.ftl0..*
Files that just need
to be copied
Place it under
!
<AndroidStudioPath>/plugins/android/lib/templates
file0..*
Template Structure
Template Folder
root
globals.xml.ftl1
recipe.xml.ftl1
template.xml1
icon.png0..*
file.ftl0..*
Place it under
!
<AndroidStudioPath>/plugins/android/lib/templates
file0..*
Template Structure
Template Folder
root
globals.xml.ftl1
recipe.xml.ftl1
template.xml1
icon.png0..*
file.ftl0..*
Files that need to be
filled with data
Place it under
!
<AndroidStudioPath>/plugins/android/lib/templates
file0..*
Template Structure
Template Folder
root
globals.xml.ftl1
recipe.xml.ftl1
template.xml1
icon.png0..*
file.ftl0..*
Place it under
!
<AndroidStudioPath>/plugins/android/lib/templates
template.xml
<template	
  
	
  	
  	
  	
  format="4"	
  
	
  	
  	
  	
  revision="1"	
  
	
  	
  	
  	
  name="Retrofit	
  Service"	
  
	
  	
  	
  	
  description="Creates	
  a	
  new	
  Retrofit	
  interface.">	
  
!
	
  	
  	
  	
  <category	
  value="Everyware"	
  />	
  
!
...	
  
!
</template>
template.xml
<parameter	
  
	
   id="className"	
  
	
   name="Interface	
  Name"	
  
	
   type="string"	
  
	
   constraints="class|unique|nonempty"	
  
	
   default="MyService"	
  />
<parameter	
  
	
   id="operationType"	
  
	
   name="Operation	
  Type"	
  
	
   type="enum"	
  
	
   constraints="nonempty"	
  
	
   default="get">	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  <option	
  id="get">GET</option>	
  
	
   <option	
  id="post">POST</option>	
  
</parameter>
template.xml
template.xml
globals.xml.ftl
<?xml	
  version="1.0"?>	
  
<globals>	
  
	
  	
  	
  	
  <global	
  id="manifestOut"	
  value="${manifestDir}"	
  />	
  
	
  	
  	
  
	
  	
  	
  	
  ...	
  
</globals>	
  
globals.xml.ftl
<?xml	
  version="1.0"?>	
  
<globals>	
  
	
  	
  	
  	
  <global	
  id="manifestOut"	
  value="${manifestDir}"	
  />	
  
	
  	
  	
  
	
  	
  	
  	
  ...	
  
</globals>	
  
FreeMarker notation
to access a variable
globals.xml.ftl
<?xml	
  version="1.0"?>	
  
<globals>	
  
	
  	
  	
  	
  <global	
  id="manifestOut"	
  value="${manifestDir}"	
  />	
  
	
  	
  	
  
	
  	
  	
  	
  ...	
  
</globals>	
  
<?xml	
  version="1.0"?>	
  
<recipe>	
  
	
  	
  	
  	
  	
  
	
   <dependency	
  mavenUrl="com.squareup.retrofit:retrofit:1.8.0"/>	
  
!
!
	
   <copy	
  from="res/values/urls.xml"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  to=“${resOut}/values/urls.xml"	
  />	
  
!
!
	
   <instantiate	
  from="src/app_package/Service.java.ftl"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  to="${srcOut}/${className}.java"	
  />	
  
!
	
  	
  	
  	
  	
  
	
   <open	
  file="${srcOut}/${className}.java"	
  />	
  
!
	
  	
  	
  	
  	
  
</recipe>
recipe.xml.ftl
<?xml	
  version="1.0"?>	
  
<recipe>	
  
	
  	
  	
  	
  	
  
	
   <dependency	
  mavenUrl="com.squareup.retrofit:retrofit:1.8.0"/>	
  
!
!
	
   <copy	
  from="res/values/urls.xml"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  to=“${resOut}/values/urls.xml"	
  />	
  
!
!
	
   <instantiate	
  from="src/app_package/Service.java.ftl"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  to="${srcOut}/${className}.java"	
  />	
  
!
	
  	
  	
  	
  	
  
	
   <open	
  file="${srcOut}/${className}.java"	
  />	
  
!
	
  	
  	
  	
  	
  
</recipe>
recipe.xml.ftl
Adds a provided dependency to
build.gradle
<?xml	
  version="1.0"?>	
  
<recipe>	
  
	
  	
  	
  	
  	
  
	
   <dependency	
  mavenUrl="com.squareup.retrofit:retrofit:1.8.0"/>	
  
!
!
	
   <copy	
  from="res/values/urls.xml"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  to=“${resOut}/values/urls.xml"	
  />	
  
!
!
	
   <instantiate	
  from="src/app_package/Service.java.ftl"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  to="${srcOut}/${className}.java"	
  />	
  
!
	
  	
  	
  	
  	
  
	
   <open	
  file="${srcOut}/${className}.java"	
  />	
  
!
	
  	
  	
  	
  	
  
</recipe>
recipe.xml.ftl
<?xml	
  version="1.0"?>	
  
<recipe>	
  
	
  	
  	
  	
  	
  
	
   <dependency	
  mavenUrl="com.squareup.retrofit:retrofit:1.8.0"/>	
  
!
!
	
   <copy	
  from="res/values/urls.xml"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  to=“${resOut}/values/urls.xml"	
  />	
  
!
!
	
   <instantiate	
  from="src/app_package/Service.java.ftl"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  to="${srcOut}/${className}.java"	
  />	
  
!
	
  	
  	
  	
  	
  
	
   <open	
  file="${srcOut}/${className}.java"	
  />	
  
!
	
  	
  	
  	
  	
  
</recipe>
recipe.xml.ftl
Copies a file without
processing
<?xml	
  version="1.0"?>	
  
<recipe>	
  
	
  	
  	
  	
  	
  
	
   <dependency	
  mavenUrl="com.squareup.retrofit:retrofit:1.8.0"/>	
  
!
!
	
   <copy	
  from="res/values/urls.xml"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  to=“${resOut}/values/urls.xml"	
  />	
  
!
!
	
   <instantiate	
  from="src/app_package/Service.java.ftl"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  to="${srcOut}/${className}.java"	
  />	
  
!
	
  	
  	
  	
  	
  
	
   <open	
  file="${srcOut}/${className}.java"	
  />	
  
!
	
  	
  	
  	
  	
  
</recipe>
recipe.xml.ftl
<?xml	
  version="1.0"?>	
  
<recipe>	
  
	
  	
  	
  	
  	
  
	
   <dependency	
  mavenUrl="com.squareup.retrofit:retrofit:1.8.0"/>	
  
!
!
	
   <copy	
  from="res/values/urls.xml"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  to=“${resOut}/values/urls.xml"	
  />	
  
!
!
	
   <instantiate	
  from="src/app_package/Service.java.ftl"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  to="${srcOut}/${className}.java"	
  />	
  
!
	
  	
  	
  	
  	
  
	
   <open	
  file="${srcOut}/${className}.java"	
  />	
  
!
	
  	
  	
  	
  	
  
</recipe>
recipe.xml.ftl
Generates a file from a template and
the provided parameters
<?xml	
  version="1.0"?>	
  
<recipe>	
  
	
  	
  	
  	
  	
  
	
   <dependency	
  mavenUrl="com.squareup.retrofit:retrofit:1.8.0"/>	
  
!
!
	
   <copy	
  from="res/values/urls.xml"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  to=“${resOut}/values/urls.xml"	
  />	
  
!
!
	
   <instantiate	
  from="src/app_package/Service.java.ftl"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  to="${srcOut}/${className}.java"	
  />	
  
!
	
  	
  	
  	
  	
  
	
   <open	
  file="${srcOut}/${className}.java"	
  />	
  
!
	
  	
  	
  	
  	
  
</recipe>
recipe.xml.ftl
<?xml	
  version="1.0"?>	
  
<recipe>	
  
	
  	
  	
  	
  	
  
	
   <dependency	
  mavenUrl="com.squareup.retrofit:retrofit:1.8.0"/>	
  
!
!
	
   <copy	
  from="res/values/urls.xml"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  to=“${resOut}/values/urls.xml"	
  />	
  
!
!
	
   <instantiate	
  from="src/app_package/Service.java.ftl"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  to="${srcOut}/${className}.java"	
  />	
  
!
	
  	
  	
  	
  	
  
	
   <open	
  file="${srcOut}/${className}.java"	
  />	
  
!
	
  	
  	
  	
  	
  
</recipe>
recipe.xml.ftl
Opens a file in the IDE
<?xml	
  version="1.0"?>	
  
<recipe>	
  
	
  	
  	
  	
  	
  
	
   <dependency	
  mavenUrl="com.squareup.retrofit:retrofit:1.8.0"/>	
  
!
!
	
   <copy	
  from="res/values/urls.xml"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  to=“${resOut}/values/urls.xml"	
  />	
  
!
!
	
   <instantiate	
  from="src/app_package/Service.java.ftl"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  to="${srcOut}/${className}.java"	
  />	
  
!
	
  	
  	
  	
  	
  
	
   <open	
  file="${srcOut}/${className}.java"	
  />	
  
!
	
  	
  	
  	
  	
  
</recipe>
recipe.xml.ftl
<?xml	
  version="1.0"?>	
  
<recipe>	
  
	
  	
  	
  	
  	
  
	
   <dependency	
  mavenUrl="com.squareup.retrofit:retrofit:1.8.0"/>	
  
!
!
	
   <copy	
  from="res/values/urls.xml"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  to=“${resOut}/values/urls.xml"	
  />	
  
!
!
	
   <instantiate	
  from="src/app_package/Service.java.ftl"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  to="${srcOut}/${className}.java"	
  />	
  
!
	
  	
  	
  	
  	
  
	
   <open	
  file="${srcOut}/${className}.java"	
  />	
  
!
	
  	
  	
  	
  	
  
</recipe>
recipe.xml.ftl
PRO TIP: Put an open command at the end of your recipe to make sure
everything executed correctly
<?xml	
  version="1.0"?>	
  
<recipe>	
  
	
  	
  	
  	
  	
  
	
   <dependency	
  mavenUrl="com.squareup.retrofit:retrofit:1.8.0"/>	
  
!
!
	
   <copy	
  from="res/values/urls.xml"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  to=“${resOut}/values/urls.xml"	
  />	
  
!
!
	
   <instantiate	
  from="src/app_package/Service.java.ftl"	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  to="${srcOut}/${className}.java"	
  />	
  
!
	
  	
  	
  	
  	
  
	
   <open	
  file="${srcOut}/${className}.java"	
  />	
  
!
	
  	
  	
  	
  	
  
</recipe>
recipe.xml.ftl
Service.java.ftl
package	
  ${packageName};	
  
!
<@imports/>	
  
!
public	
  interface	
  ${className}{	
  
	
  	
  	
  	
  	
  
	
  	
  	
  	
  <@multipart/>	
  
	
  	
  	
  	
  <@operation/>	
  
	
  	
  	
  	
  <@methodSignature/>	
  
	
  	
  	
  	
  	
  
}
<#macro	
  imports>	
  
<#if	
  operationType="get">	
  
import	
  retrofit.http.GET;	
  
<#else/>	
  
import	
  retrofit.http.POST;	
  
</#if>	
  
...	
  
</#macro>
<#macro	
  methodSignature>	
  
	
  	
  	
  	
  public	
  <@output/>	
  ${methodName}(<@methodParameters/>);	
  
</#macro>
ADT Templates
Generates multiple files, even projects
Customizable
Only for creation
Automatic UI wizard generated
Complex syntax
Difficult to test and verify correctness
GRADLE PLUGINS
apply	
  plugin:	
  SimplePlugin	
  
!
class	
  SimplePlugin	
  implements	
  Plugin<Project>	
  {	
  
	
  	
  	
  	
  void	
  apply(Project	
  project)	
  {	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  println	
  "Hello	
  World!"	
  
!
	
  	
  	
  	
  }	
  
}
Gradle Plugin
apply	
  plugin:	
  SimplePlugin	
  
!
class	
  SimplePlugin	
  implements	
  Plugin<Project>	
  {	
  
	
  	
  	
  	
  void	
  apply(Project	
  project)	
  {	
  
!
	
   	
   def	
  hasApp	
  =	
  project.plugins.withType(AppPlugin)	
  
	
   	
   def	
  hasLib	
  =	
  project.plugins.withType(LibraryPlugin)	
  
	
   	
   if	
  (!hasApp	
  &&	
  !hasLib)	
  {	
  
	
   	
   	
   throw	
  new	
  IllegalStateException("'android'	
  or	
  'android-­‐
library'	
  plugin	
  required.")	
  
	
   	
   }	
  
!
	
  	
  	
  	
  }	
  
}
Checking Android plugin dependencies
Adding dependencies
apply	
  plugin:	
  SimplePlugin	
  
!
class	
  SimplePlugin	
  implements	
  Plugin<Project>	
  {	
  
	
  	
  	
  	
  void	
  apply(Project	
  project)	
  {	
  
!
	
   	
   project.dependencies	
  {	
  
	
   	
   	
   debugCompile	
  'your-­‐dependency'	
  
	
   	
   	
   compile	
  'your-­‐dependency'	
  
	
   	
   }	
  
!
	
  	
  	
  	
  }	
  
}
apply	
  plugin:	
  SimplePlugin	
  
!
class	
  SimplePlugin	
  implements	
  Plugin<Project>	
  {	
  
	
  	
  	
  	
  void	
  apply(Project	
  project)	
  {	
  
!
	
   	
   project.extensions.create('myextension',	
  	
  
	
   	
   	
   	
   	
   	
   	
   	
   	
   	
   	
  SimpleExtension)	
  
!
	
  	
  	
  	
  }	
  
}	
  
!
class	
  SimpleExtension	
  {	
  
	
   int	
  aNumber	
  =	
  0	
  
	
   List<String>	
  aList	
  =	
  []	
  
}
Adding extensions
Adding extensions
apply	
  plugin:	
  'com.android.application'	
  
apply	
  plugin:	
  SimplePlugin	
  
!
android	
  {	
  
	
  	
  	
  	
  compileSdkVersion	
  21	
  
	
  	
  	
  	
  buildToolsVersion	
  "21.1.2"	
  
!
	
  	
  	
  	
  defaultConfig	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  applicationId	
  "es.everywaretech.myapplication"	
  
	
  	
  	
  	
  	
  	
  	
  	
  minSdkVersion	
  15	
  
	
  	
  	
  	
  	
  	
  	
  	
  targetSdkVersion	
  21	
  
	
  	
  	
  	
  	
  	
  	
  	
  versionCode	
  1	
  
	
  	
  	
  	
  	
  	
  	
  	
  versionName	
  "1.0"	
  
	
  	
  	
  	
  }	
  
}	
  
...	
  
myextension{	
  
	
   aNumber	
  =	
  42	
  
	
   aList	
  =	
  ["Hello",	
  "World"]	
  
}
Iterating through Variants
apply	
  plugin:	
  SimplePlugin	
  
!
class	
  SimplePlugin	
  implements	
  Plugin<Project>	
  {	
  
	
  	
  	
  	
  void	
  apply(Project	
  project)	
  {	
  
!
	
   	
   variants.all	
  {	
  variant	
  -­‐>	
  
	
   	
   	
   if	
  (!variant.buildType.isDebuggable())	
  {	
  
	
   	
   	
   	
   //	
  Do	
  something	
  with	
  Debug	
  variant	
  
	
   	
   	
   }else{	
  
	
   	
   	
   	
   //	
  Do	
  something	
  with	
  Release	
  variant	
  
	
   	
   	
   }	
  
	
   	
   }	
  
!
	
  	
  	
  	
  }	
  
}
Creating custom tasks
class	
  SimpleTask	
  extends	
  DefaultTask	
  {	
  
	
  	
  	
  	
  String	
  greeting	
  =	
  'Hello	
  World'	
  
!
	
  	
  	
  	
  @TaskAction	
  
	
  	
  	
  	
  def	
  greet()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  println	
  greeting	
  
	
  	
  	
  	
  }	
  
}	
  
!
//	
  Use	
  the	
  default	
  task	
  
task	
  hello(type:	
  SimpleTask)	
  
!
//	
  Customize	
  the	
  task	
  
task	
  droidcon(type:	
  SimpleTask)	
  {	
  
	
  	
  	
  	
  greeting	
  =	
  'Hello	
  Droidcon'	
  
}
Creating custom incremental tasks
class	
  MyIncrementalTask	
  extends	
  DefaultTask	
  {	
  
	
  	
  	
  	
  @InputDirectory	
  
	
  	
  	
  	
  def	
  File	
  inputDir	
  
!
	
  	
  	
  	
  @OutputDirectory	
  
	
  	
  	
  	
  def	
  File	
  outputDir	
  
!
	
  	
  	
  	
  @Input	
  
	
  	
  	
  	
  def	
  inputProperty	
  
!
	
  	
  	
  	
  @TaskAction	
  
	
  	
  	
  	
  void	
  execute(IncrementalTaskInputs	
  inputs)	
  {	
  
	
   	
   	
   if(inputs.incremental){	
  
	
   	
   	
   	
   //	
  Only	
  changed	
  files	
  will	
  be	
  provided	
  
	
   	
   	
   }else{	
  
	
   	
   	
   	
   //	
  All	
  files	
  will	
  be	
  provided	
  
	
   	
   	
   }	
  
	
  	
  	
  	
  	
  	
  	
  	
   ...	
  
	
  	
  	
  	
  }	
  
}
Warning! Incubating feature
Creating custom incremental tasks
class	
  MyIncrementalTask	
  extends	
  DefaultTask	
  {	
  
	
  	
  	
  	
  ...	
  
!
	
  	
  	
  	
  @TaskAction	
  
	
  	
  	
  	
  void	
  execute(IncrementalTaskInputs	
  inputs)	
  {	
  
	
   	
   	
  	
  ...	
  
	
  	
  	
  	
  	
  	
  	
  	
  inputs.outOfDate	
  {	
  change	
  -­‐>	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //	
  Do	
  something	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
!
	
  	
  	
  	
  	
  	
  	
  	
  inputs.removed	
  {	
  change	
  -­‐>	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  //	
  Do	
  something	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  
}
Warning! Incubating feature
Gradle Plugins
Helps with recurring building tasks
Not only for source code, also other
resources
Only available at build time
ANNOTATION!
PROCESSORS
Using annotations
@Nullable	
  
@Override	
  
public	
  View	
  onCreateView(String	
  name,	
  	
  
	
   	
   	
   	
   	
   	
   	
   	
  	
  @NonNull	
  Context	
  context,	
  	
  
	
   	
   	
   	
   	
   	
   	
   	
  	
  @NonNull	
  AttributeSet	
  attrs)	
  {	
  
	
   ...	
  
}	
  
Using annotations
@Nullable	
  
@Override	
  
public	
  View	
  onCreateView(String	
  name,	
  	
  
	
   	
   	
   	
   	
   	
   	
   	
  	
  @NonNull	
  Context	
  context,	
  	
  
	
   	
   	
   	
   	
   	
   	
   	
  	
  @NonNull	
  AttributeSet	
  attrs)	
  {	
  
	
   ...	
  
}	
  
PRO TIP: Use Support Annotations
!
dependencies	
  {	
  
	
  	
  	
  	
  compile	
  'com.android.support:support-­‐annotations:20.0.0'	
  
}
Using annotations
@Nullable	
  
@Override	
  
public	
  View	
  onCreateView(String	
  name,	
  	
  
	
   	
   	
   	
   	
   	
   	
   	
  	
  @NonNull	
  Context	
  context,	
  	
  
	
   	
   	
   	
   	
   	
   	
   	
  	
  @NonNull	
  AttributeSet	
  attrs)	
  {	
  
	
   ...	
  
}	
  
Defining annotations types
@Retention(Retention.{SOURCE|CLASS|RUNTIME})	
  
@Target(ElementType.{ANNOTATION_TYPE|CONSTRUCTOR|FIELD|	
  
	
   	
   	
   	
   	
   	
   	
  	
  LOCAL_VARIABLE|METHOD|PACKAGE|	
  
	
   	
   	
   	
   	
   	
   	
  	
  PARAMETER|TYPE})	
  
public	
  @interface	
  MyAnnotation{	
  
	
   String	
  value()	
  default	
  "some	
  string";	
  
	
   int	
  number()	
  default	
  0;	
  
}	
  
!
@MyAnnotation("another	
  string",	
  number	
  =	
  42)	
  
public	
  class	
  MyClass{	
  
	
   ...	
  
}
Processing annotations
public	
  interface	
  Processor{	
  
!
	
   Iterable<?	
  extends	
  Completion>	
  getCompletions(Element	
  element,	
  
	
   	
   AnnotationMirror	
  annotation,	
  	
  
	
   	
   ExecutableElement	
  member,	
  	
  
	
   	
   String	
  userText);	
  
!
	
   Set<String>	
  getSupportedAnnotationTypes();	
  
!
	
   Set<String>	
  getSupportedOptions();	
  
!
	
   SourceVersion	
  getSupportedSourceVersion();	
  
!
	
   void	
  init(ProcessingEnvironment	
  processingEnv);	
  
!
	
   boolean	
  process(Set<?	
  extends	
  TypeElement>	
  annotations,	
  	
  
	
   	
   RoundEnvironment	
  roundEnv);	
  
!
}
Processing annotations
public	
  interface	
  Processor{	
  
!
	
   Iterable<?	
  extends	
  Completion>	
  getCompletions(Element	
  element,	
  
	
   	
   AnnotationMirror	
  annotation,	
  	
  
	
   	
   ExecutableElement	
  member,	
  	
  
	
   	
   String	
  userText);	
  
!
	
   Set<String>	
  getSupportedAnnotationTypes();	
  
!
	
   Set<String>	
  getSupportedOptions();	
  
!
	
   SourceVersion	
  getSupportedSourceVersion();	
  
!
	
   void	
  init(ProcessingEnvironment	
  processingEnv);	
  
!
	
   boolean	
  process(Set<?	
  extends	
  TypeElement>	
  annotations,	
  	
  
	
   	
   RoundEnvironment	
  roundEnv);	
  
!
}
Suggestions for the IDE to
complete an annotation
Processing annotations
public	
  interface	
  Processor{	
  
!
	
   Iterable<?	
  extends	
  Completion>	
  getCompletions(Element	
  element,	
  
	
   	
   AnnotationMirror	
  annotation,	
  	
  
	
   	
   ExecutableElement	
  member,	
  	
  
	
   	
   String	
  userText);	
  
!
	
   Set<String>	
  getSupportedAnnotationTypes();	
  
!
	
   Set<String>	
  getSupportedOptions();	
  
!
	
   SourceVersion	
  getSupportedSourceVersion();	
  
!
	
   void	
  init(ProcessingEnvironment	
  processingEnv);	
  
!
	
   boolean	
  process(Set<?	
  extends	
  TypeElement>	
  annotations,	
  	
  
	
   	
   RoundEnvironment	
  roundEnv);	
  
!
}
Processing annotations
public	
  interface	
  Processor{	
  
!
	
   Iterable<?	
  extends	
  Completion>	
  getCompletions(Element	
  element,	
  
	
   	
   AnnotationMirror	
  annotation,	
  	
  
	
   	
   ExecutableElement	
  member,	
  	
  
	
   	
   String	
  userText);	
  
!
	
   Set<String>	
  getSupportedAnnotationTypes();	
  
!
	
   Set<String>	
  getSupportedOptions();	
  
!
	
   SourceVersion	
  getSupportedSourceVersion();	
  
!
	
   void	
  init(ProcessingEnvironment	
  processingEnv);	
  
!
	
   boolean	
  process(Set<?	
  extends	
  TypeElement>	
  annotations,	
  	
  
	
   	
   RoundEnvironment	
  roundEnv);	
  
!
}
Annotations that this
Processor is able to handle
Processing annotations
public	
  interface	
  Processor{	
  
!
	
   Iterable<?	
  extends	
  Completion>	
  getCompletions(Element	
  element,	
  
	
   	
   AnnotationMirror	
  annotation,	
  	
  
	
   	
   ExecutableElement	
  member,	
  	
  
	
   	
   String	
  userText);	
  
!
	
   Set<String>	
  getSupportedAnnotationTypes();	
  
!
	
   Set<String>	
  getSupportedOptions();	
  
!
	
   SourceVersion	
  getSupportedSourceVersion();	
  
!
	
   void	
  init(ProcessingEnvironment	
  processingEnv);	
  
!
	
   boolean	
  process(Set<?	
  extends	
  TypeElement>	
  annotations,	
  	
  
	
   	
   RoundEnvironment	
  roundEnv);	
  
!
}
Processing annotations
public	
  interface	
  Processor{	
  
!
	
   Iterable<?	
  extends	
  Completion>	
  getCompletions(Element	
  element,	
  
	
   	
   AnnotationMirror	
  annotation,	
  	
  
	
   	
   ExecutableElement	
  member,	
  	
  
	
   	
   String	
  userText);	
  
!
	
   Set<String>	
  getSupportedAnnotationTypes();	
  
!
	
   Set<String>	
  getSupportedOptions();	
  
!
	
   SourceVersion	
  getSupportedSourceVersion();	
  
!
	
   void	
  init(ProcessingEnvironment	
  processingEnv);	
  
!
	
   boolean	
  process(Set<?	
  extends	
  TypeElement>	
  annotations,	
  	
  
	
   	
   RoundEnvironment	
  roundEnv);	
  
!
}
Processor
initialization
Processing annotations
public	
  interface	
  Processor{	
  
!
	
   Iterable<?	
  extends	
  Completion>	
  getCompletions(Element	
  element,	
  
	
   	
   AnnotationMirror	
  annotation,	
  	
  
	
   	
   ExecutableElement	
  member,	
  	
  
	
   	
   String	
  userText);	
  
!
	
   Set<String>	
  getSupportedAnnotationTypes();	
  
!
	
   Set<String>	
  getSupportedOptions();	
  
!
	
   SourceVersion	
  getSupportedSourceVersion();	
  
!
	
   void	
  init(ProcessingEnvironment	
  processingEnv);	
  
!
	
   boolean	
  process(Set<?	
  extends	
  TypeElement>	
  annotations,	
  	
  
	
   	
   RoundEnvironment	
  roundEnv);	
  
!
}
Processing annotations
public	
  interface	
  Processor{	
  
!
	
   Iterable<?	
  extends	
  Completion>	
  getCompletions(Element	
  element,	
  
	
   	
   AnnotationMirror	
  annotation,	
  	
  
	
   	
   ExecutableElement	
  member,	
  	
  
	
   	
   String	
  userText);	
  
!
	
   Set<String>	
  getSupportedAnnotationTypes();	
  
!
	
   Set<String>	
  getSupportedOptions();	
  
!
	
   SourceVersion	
  getSupportedSourceVersion();	
  
!
	
   void	
  init(ProcessingEnvironment	
  processingEnv);	
  
!
	
   boolean	
  process(Set<?	
  extends	
  TypeElement>	
  annotations,	
  	
  
	
   	
   RoundEnvironment	
  roundEnv);	
  
!
}
Inspection of the annotations
and code generation
Processing annotations
public	
  interface	
  Processor{	
  
!
	
   Iterable<?	
  extends	
  Completion>	
  getCompletions(Element	
  element,	
  
	
   	
   AnnotationMirror	
  annotation,	
  	
  
	
   	
   ExecutableElement	
  member,	
  	
  
	
   	
   String	
  userText);	
  
!
	
   Set<String>	
  getSupportedAnnotationTypes();	
  
!
	
   Set<String>	
  getSupportedOptions();	
  
!
	
   SourceVersion	
  getSupportedSourceVersion();	
  
!
	
   void	
  init(ProcessingEnvironment	
  processingEnv);	
  
!
	
   boolean	
  process(Set<?	
  extends	
  TypeElement>	
  annotations,	
  	
  
	
   	
   RoundEnvironment	
  roundEnv);	
  
!
}
Processing annotations
public	
  interface	
  ProcessingEnvironment{	
  
	
   	
  
	
   Elements	
  getElementUtils();	
  
!
	
   Filer	
  getFiler();	
  
!
	
   Locale	
  getLocale();	
  
!
	
   Messager	
  getMessager();	
  
!
	
   Map<String,String>	
  getOptions();	
  
!
	
   SourceVersion	
  getSourceVersion();	
  
!
	
   Types	
  getTypeUtils();	
  
}
Processing annotations
public	
  interface	
  ProcessingEnvironment{	
  
	
   	
  
	
   Elements	
  getElementUtils();	
  
!
	
   Filer	
  getFiler();	
  
!
	
   Locale	
  getLocale();	
  
!
	
   Messager	
  getMessager();	
  
!
	
   Map<String,String>	
  getOptions();	
  
!
	
   SourceVersion	
  getSourceVersion();	
  
!
	
   Types	
  getTypeUtils();	
  
}
Creation of new Files
Processing annotations
public	
  interface	
  ProcessingEnvironment{	
  
	
   	
  
	
   Elements	
  getElementUtils();	
  
!
	
   Filer	
  getFiler();	
  
!
	
   Locale	
  getLocale();	
  
!
	
   Messager	
  getMessager();	
  
!
	
   Map<String,String>	
  getOptions();	
  
!
	
   SourceVersion	
  getSourceVersion();	
  
!
	
   Types	
  getTypeUtils();	
  
}
Processing annotations
public	
  interface	
  ProcessingEnvironment{	
  
	
   	
  
	
   Elements	
  getElementUtils();	
  
!
	
   Filer	
  getFiler();	
  
!
	
   Locale	
  getLocale();	
  
!
	
   Messager	
  getMessager();	
  
!
	
   Map<String,String>	
  getOptions();	
  
!
	
   SourceVersion	
  getSourceVersion();	
  
!
	
   Types	
  getTypeUtils();	
  
}
Writing warnings and
errors
Processing annotations
public	
  interface	
  ProcessingEnvironment{	
  
	
   	
  
	
   Elements	
  getElementUtils();	
  
!
	
   Filer	
  getFiler();	
  
!
	
   Locale	
  getLocale();	
  
!
	
   Messager	
  getMessager();	
  
!
	
   Map<String,String>	
  getOptions();	
  
!
	
   SourceVersion	
  getSourceVersion();	
  
!
	
   Types	
  getTypeUtils();	
  
}
Processing annotations
@AutoService(Processor.class)	
  
public	
  class	
  MyProcessor{	
  
!
	
   @Override	
  public	
  Set<String>	
  getSupportedAnnotationTypes(){	
  
	
   	
   return	
  Collections.singleton(MyAnnotation.class.getName());	
  
	
   }	
  
!
	
   @Override	
  public	
  SourceVersion	
  getSupportedSourceVersion(){	
  
	
   	
   return	
  SourceVersion.latestSupported();	
  
	
   }	
  
!
	
   @Override	
  public	
  boolean	
  process(Set<?	
  extends	
  TypeElement>	
  
annotations,	
  RoundEnvironment	
  roundEnv){	
  
!
	
   	
   Set<?	
  extends	
  Element>	
  elements	
  	
  
	
   	
   	
   =	
  roundEnv.getElementsAnnotatedWith(MyAnnotation.class);	
  
	
   	
   //	
  Process	
  elements	
  and	
  generate	
  code	
  
!
	
   	
   return	
  false;	
  
	
   }	
  
}
Processing annotations
@AutoService(Processor.class)	
  
public	
  class	
  MyProcessor{	
  
!
	
   @Override	
  public	
  Set<String>	
  getSupportedAnnotationTypes(){	
  
	
   	
   return	
  Collections.singleton(MyAnnotation.class.getName());	
  
	
   }	
  
!
	
   @Override	
  public	
  SourceVersion	
  getSupportedSourceVersion(){	
  
	
   	
   return	
  SourceVersion.latestSupported();	
  
	
   }	
  
!
	
   @Override	
  public	
  boolean	
  process(Set<?	
  extends	
  TypeElement>	
  
annotations,	
  RoundEnvironment	
  roundEnv){	
  
!
	
   	
   Set<?	
  extends	
  Element>	
  elements	
  	
  
	
   	
   	
   =	
  roundEnv.getElementsAnnotatedWith(MyAnnotation.class);	
  
	
   	
   //	
  Process	
  elements	
  and	
  generate	
  code	
  
!
	
   	
   return	
  false;	
  
	
   }	
  
}
PRO TIP: Use com.squareup.JavaPoet
to generate code
Processing annotations
@AutoService(Processor.class)	
  
public	
  class	
  MyProcessor{	
  
!
	
   @Override	
  public	
  Set<String>	
  getSupportedAnnotationTypes(){	
  
	
   	
   return	
  Collections.singleton(MyAnnotation.class.getName());	
  
	
   }	
  
!
	
   @Override	
  public	
  SourceVersion	
  getSupportedSourceVersion(){	
  
	
   	
   return	
  SourceVersion.latestSupported();	
  
	
   }	
  
!
	
   @Override	
  public	
  boolean	
  process(Set<?	
  extends	
  TypeElement>	
  
annotations,	
  RoundEnvironment	
  roundEnv){	
  
!
	
   	
   Set<?	
  extends	
  Element>	
  elements	
  	
  
	
   	
   	
   =	
  roundEnv.getElementsAnnotatedWith(MyAnnotation.class);	
  
	
   	
   //	
  Process	
  elements	
  and	
  generate	
  code	
  
!
	
   	
   return	
  false;	
  
	
   }	
  
}
Processing annotations
@AutoService(Processor.class)	
  
public	
  class	
  MyProcessor{	
  
!
	
   @Override	
  public	
  Set<String>	
  getSupportedAnnotationTypes(){	
  
	
   	
   return	
  Collections.singleton(MyAnnotation.class.getName());	
  
	
   }	
  
!
	
   @Override	
  public	
  SourceVersion	
  getSupportedSourceVersion(){	
  
	
   	
   return	
  SourceVersion.latestSupported();	
  
	
   }	
  
!
	
   @Override	
  public	
  boolean	
  process(Set<?	
  extends	
  TypeElement>	
  
annotations,	
  RoundEnvironment	
  roundEnv){	
  
!
	
   	
   Set<?	
  extends	
  Element>	
  elements	
  	
  
	
   	
   	
   =	
  roundEnv.getElementsAnnotatedWith(MyAnnotation.class);	
  
	
   	
   //	
  Process	
  elements	
  and	
  generate	
  code	
  
!
	
   	
   return	
  false;	
  
	
   }	
  
}
Allows other processors to
handle the same annotations
Processing annotations
@AutoService(Processor.class)	
  
public	
  class	
  MyProcessor{	
  
!
	
   @Override	
  public	
  Set<String>	
  getSupportedAnnotationTypes(){	
  
	
   	
   return	
  Collections.singleton(MyAnnotation.class.getName());	
  
	
   }	
  
!
	
   @Override	
  public	
  SourceVersion	
  getSupportedSourceVersion(){	
  
	
   	
   return	
  SourceVersion.latestSupported();	
  
	
   }	
  
!
	
   @Override	
  public	
  boolean	
  process(Set<?	
  extends	
  TypeElement>	
  
annotations,	
  RoundEnvironment	
  roundEnv){	
  
!
	
   	
   Set<?	
  extends	
  Element>	
  elements	
  	
  
	
   	
   	
   =	
  roundEnv.getElementsAnnotatedWith(MyAnnotation.class);	
  
	
   	
   //	
  Process	
  elements	
  and	
  generate	
  code	
  
!
	
   	
   return	
  false;	
  
	
   }	
  
}
Processing annotations
@AutoService(Processor.class)	
  
public	
  class	
  MyProcessor{	
  
!
	
   @Override	
  public	
  Set<String>	
  getSupportedAnnotationTypes(){	
  
	
   	
   return	
  Collections.singleton(MyAnnotation.class.getName());	
  
	
   }	
  
!
	
   @Override	
  public	
  SourceVersion	
  getSupportedSourceVersion(){	
  
	
   	
   return	
  SourceVersion.latestSupported();	
  
	
   }	
  
!
	
   @Override	
  public	
  boolean	
  process(Set<?	
  extends	
  TypeElement>	
  
annotations,	
  RoundEnvironment	
  roundEnv){	
  
!
	
   	
   Set<?	
  extends	
  Element>	
  elements	
  	
  
	
   	
   	
   =	
  roundEnv.getElementsAnnotatedWith(MyAnnotation.class);	
  
	
   	
   //	
  Process	
  elements	
  and	
  generate	
  code	
  
!
	
   	
   return	
  false;	
  
	
   }	
  
}
PRO TIP: Use AutoService
to generate META-INF
Processing annotations
@AutoService(Processor.class)	
  
public	
  class	
  MyProcessor{	
  
!
	
   @Override	
  public	
  Set<String>	
  getSupportedAnnotationTypes(){	
  
	
   	
   return	
  Collections.singleton(MyAnnotation.class.getName());	
  
	
   }	
  
!
	
   @Override	
  public	
  SourceVersion	
  getSupportedSourceVersion(){	
  
	
   	
   return	
  SourceVersion.latestSupported();	
  
	
   }	
  
!
	
   @Override	
  public	
  boolean	
  process(Set<?	
  extends	
  TypeElement>	
  
annotations,	
  RoundEnvironment	
  roundEnv){	
  
!
	
   	
   Set<?	
  extends	
  Element>	
  elements	
  	
  
	
   	
   	
   =	
  roundEnv.getElementsAnnotatedWith(MyAnnotation.class);	
  
	
   	
   //	
  Process	
  elements	
  and	
  generate	
  code	
  
!
	
   	
   return	
  false;	
  
	
   }	
  
}
Generation process
javac
MyProcessor YourProcessor
A.java
javac
MyProcessor YourProcessor
A.java
A.class
Generation process
javac
MyProcessor YourProcessor
A.java
A.class
B.java
Generation process
javac
MyProcessor YourProcessor
A.java
A.class
B.java
B.class
Generation process
javac
MyProcessor YourProcessor
A.java
A.class
B.java
B.class
C.java
Generation process
javac
MyProcessor YourProcessor
A.java
A.class
B.java
B.class
C.java
C.class
Generation process
javac
MyProcessor YourProcessor
A.java
A.class
B.java
B.class
C.java
C.class
Generation process
Annotation Processors
Java feature, IDE independent
Not only for source code, also other
resources
Expensive if done at runtime
Testable
IDE PLUGINS
Extending AnAction
public	
  class	
  MyAction	
  extends	
  AnAction	
  {	
  
	
   @Override	
  
	
   public	
  void	
  actionPerformed(AnActionEvent	
  e)	
  {	
  
!
	
   }	
  
}	
  
Retrieve the selected element
public	
  class	
  MyAction	
  extends	
  AnAction	
  {	
  
	
   @Override	
  
	
   public	
  void	
  actionPerformed(AnActionEvent	
  e)	
  {	
  
!
	
   	
   PsiFile	
  psiFile	
  =	
  e.getData(LangDataKeys.PSI_FILE);	
  
	
   	
   Editor	
  editor	
  =	
  e.getData(PlatformDataKeys.EDITOR);	
  
!
	
   	
   if	
  (psiFile	
  ==	
  null	
  ||	
  editor	
  ==	
  null)	
  {	
  
	
   	
   	
   return;	
  
	
   	
   }	
  
!
	
   	
   int	
  offset	
  =	
  editor.getCaretModel().getOffset();	
  
	
   	
   PsiElement	
  element	
  =	
  psiFile.findElementAt(offset);	
  
!
	
   }	
  
}	
  
Retrieve the selected class
public	
  class	
  MyAction	
  extends	
  AnAction	
  {	
  
	
   @Override	
  
	
   public	
  void	
  actionPerformed(AnActionEvent	
  e)	
  {	
  
!
	
   	
   PsiFile	
  psiFile	
  =	
  e.getData(LangDataKeys.PSI_FILE);	
  
	
   	
   Editor	
  editor	
  =	
  e.getData(PlatformDataKeys.EDITOR);	
  
!
	
   	
   if	
  (psiFile	
  ==	
  null	
  ||	
  editor	
  ==	
  null)	
  {	
  
	
   	
   	
   return;	
  
	
   	
   }	
  
!
	
   	
   int	
  offset	
  =	
  editor.getCaretModel().getOffset();	
  
	
   	
   PsiElement	
  element	
  =	
  psiFile.findElementAt(offset);	
  
!
	
   	
   PsiClass	
  psiClass	
  =	
  PsiTreeUtil.getParentOfType(element,	
  
PsiClass.class);	
  
!
	
   }	
  
}	
  
Generate code
public	
  class	
  MyAction	
  extends	
  AnAction	
  {	
  
	
   @Override	
  
	
   public	
  void	
  actionPerformed(AnActionEvent	
  e)	
  {	
  
!
	
   	
   ...	
  
!
	
   	
   new	
  WriteCommandAction.Simple(psiClass.getProject(),	
  
psiClass.getContainingFile())	
  {	
  
	
   	
   	
   @Override	
  
	
   	
   	
   protected	
  void	
  run()	
  throws	
  Throwable	
  {	
  
	
   	
   	
   	
   generateCode(psiClass);	
  
	
   	
   	
   }	
  
	
   	
   }.execute();	
  
	
   }	
  
}	
  
Generate code
public	
  void	
  generateCode(PsiClass	
  psiClass){	
  
	
   PsiElementFactory	
  elementFactory	
  =	
  	
  
	
   	
   JavaPsiFacade.getElementFactory(psiClass.getProject());	
  
!
	
   PsiMethod	
  myMethod	
  =	
  	
  
	
   	
   elementFactory.createMethodFromText(methodCode,	
  psiClass);	
  
!
	
   PsiField	
  myField	
  =	
  
	
   	
   elementFactory.createFieldFromText(fieldCode,	
  psiClass);	
  
!
	
   ...	
  
}
Generate code
public	
  void	
  generateCode(PsiClass	
  psiClass){	
  
	
   ...	
  
!
	
   JavaCodeStyleManager	
  styleManager	
  =	
  	
  
	
   	
   JavaCodeStyleManager.getInstance(psiClass.getProject());	
  
!
	
   styleManager.shortenClassReferences(	
  
	
   	
   psiClass.addBefore(myMethod,	
  psiClass.getLastChild()));	
  
!
	
   styleManager.shortenClassReferences(	
  
	
   	
   psiClass.addBefore(myField,	
  psiClass.getLastChild()));	
  
}
Register action
<idea-­‐plugin	
  version="4">	
  
	
   <id>com.example.myplugin</id>	
  
	
   <name>Droidcon	
  Plugin</name>	
  
	
   <version>1.0</version>	
  
	
   <vendor	
  email="tomas@everywaretech.es"	
  
	
   	
   	
   	
  	
  url="http://www.everywaretech.es">	
  
	
   	
   Tomás	
  Ruiz-­‐López	
  
	
   </vendor>	
  
!
	
   <actions>	
  
	
   	
   <action	
  id="myplugin"	
  	
  
	
   	
   	
   class="es.everywaretech.myplugin"	
  
	
   	
   	
   text="MyPlugin"	
  
	
   	
   	
   description="Generates	
  Boilerplate	
  Code">	
  
!
	
   	
   	
   <add-­‐to-­‐group	
  group-­‐id="MainMenu"	
  anchor="last"/>	
  
	
   	
   </action>	
  
	
   </actions>	
  
</idea-­‐plugin>	
  
plugin.xml
Register action
<idea-­‐plugin	
  version="4">	
  
	
   <id>com.example.myplugin</id>	
  
	
   <name>Droidcon	
  Plugin</name>	
  
	
   <version>1.0</version>	
  
	
   <vendor	
  email="tomas@everywaretech.es"	
  
	
   	
   	
   	
  	
  url="http://www.everywaretech.es">	
  
	
   	
   Tomás	
  Ruiz-­‐López	
  
	
   </vendor>	
  
!
	
   <actions>	
  
	
   	
   <action	
  id="myplugin"	
  	
  
	
   	
   	
   class="es.everywaretech.myplugin"	
  
	
   	
   	
   text="MyPlugin"	
  
	
   	
   	
   description="Generates	
  Boilerplate	
  Code">	
  
!
	
   	
   	
   <add-­‐to-­‐group	
  group-­‐id="MainMenu"	
  anchor="last"/>	
  
	
   	
   </action>	
  
	
   </actions>	
  
</idea-­‐plugin>	
  
See
com.intellij.openapi.actionSystem.ActionPlaces	
  
for more group ids
plugin.xml
Register action
<idea-­‐plugin	
  version="4">	
  
	
   <id>com.example.myplugin</id>	
  
	
   <name>Droidcon	
  Plugin</name>	
  
	
   <version>1.0</version>	
  
	
   <vendor	
  email="tomas@everywaretech.es"	
  
	
   	
   	
   	
  	
  url="http://www.everywaretech.es">	
  
	
   	
   Tomás	
  Ruiz-­‐López	
  
	
   </vendor>	
  
!
	
   <actions>	
  
	
   	
   <action	
  id="myplugin"	
  	
  
	
   	
   	
   class="es.everywaretech.myplugin"	
  
	
   	
   	
   text="MyPlugin"	
  
	
   	
   	
   description="Generates	
  Boilerplate	
  Code">	
  
!
	
   	
   	
   <add-­‐to-­‐group	
  group-­‐id="MainMenu"	
  anchor="last"/>	
  
	
   	
   </action>	
  
	
   </actions>	
  
</idea-­‐plugin>	
  
plugin.xml
IDE Plugins
More flexible
Fine and coarse grained code generation
More complex to develop
Only for IntelliJ or Android Studio
LEARN MORE
About ADT Templates
Official documentation
https://android.googlesource.com/platform/sdk/+/refs/heads/master/templates/docs/index.html
About Gradle Plugins
Writing Custom Plugins
https://gradle.org/docs/current/userguide/custom_plugins.html
!
Lessons learned from our first Gradle plugin for Android,
Victor
https://trello.engineering/victor/
!
Hugo
https://github.com/JakeWharton/hugo
About Annotation Processors
Annotation Processing Boilerplate Destruction
https://speakerdeck.com/jakewharton/annotation-processing-boilerplate-destruction-droidcon-nyc-2014
About IntelliJ Plugins
Getting Started with Plugin Development
https://confluence.jetbrains.com/display/IDEADEV/Getting+Started+with+Plugin+Development
!
Thanks!
QUESTIONS?
Tomás Ruiz López
Everyware Technologies
Droidcon Spain 2015@tomasruizlopez
tomas@everywaretech.es

More Related Content

What's hot

Rest API using Flask & SqlAlchemy
Rest API using Flask & SqlAlchemyRest API using Flask & SqlAlchemy
Rest API using Flask & SqlAlchemy
Alessandro Cucci
 
Go swagger tutorial how to create golang api documentation using go swagger (1)
Go swagger tutorial how to create golang api documentation using go swagger (1)Go swagger tutorial how to create golang api documentation using go swagger (1)
Go swagger tutorial how to create golang api documentation using go swagger (1)
Katy Slemon
 
Php 7.2 compliance workshop php benelux
Php 7.2 compliance workshop php beneluxPhp 7.2 compliance workshop php benelux
Php 7.2 compliance workshop php benelux
Damien Seguy
 
Build restful ap is with python and flask
Build restful ap is with python and flaskBuild restful ap is with python and flask
Build restful ap is with python and flask
Jeetendra singh
 
Developing Drizzle Replication Plugins
Developing Drizzle Replication PluginsDeveloping Drizzle Replication Plugins
Developing Drizzle Replication Plugins
Padraig O'Sullivan
 
3 introduction-php-mvc-cakephp-m3-getting-started-slides
3 introduction-php-mvc-cakephp-m3-getting-started-slides3 introduction-php-mvc-cakephp-m3-getting-started-slides
3 introduction-php-mvc-cakephp-m3-getting-started-slidesMasterCode.vn
 
Flask Basics
Flask BasicsFlask Basics
Flask Basics
Eueung Mulyana
 
It's a Kind of Magic: Under the Covers of Spring Boot
It's a Kind of Magic: Under the Covers of Spring BootIt's a Kind of Magic: Under the Covers of Spring Boot
It's a Kind of Magic: Under the Covers of Spring Boot
VMware Tanzu
 
Php Debugger
Php DebuggerPhp Debugger
Php Debugger
guest8cd374
 
4 introduction-php-mvc-cakephp-m4-controllers-slides
4 introduction-php-mvc-cakephp-m4-controllers-slides4 introduction-php-mvc-cakephp-m4-controllers-slides
4 introduction-php-mvc-cakephp-m4-controllers-slidesMasterCode.vn
 
React mit TypeScript – eine glückliche Ehe
React mit TypeScript – eine glückliche EheReact mit TypeScript – eine glückliche Ehe
React mit TypeScript – eine glückliche Ehe
inovex GmbH
 
Flask Introduction - Python Meetup
Flask Introduction - Python MeetupFlask Introduction - Python Meetup
Flask Introduction - Python Meetup
Areski Belaid
 
PHPUnit with CakePHP and Yii
PHPUnit with CakePHP and YiiPHPUnit with CakePHP and Yii
PHPUnit with CakePHP and Yii
madhavi Ghadge
 
Learn flask in 90mins
Learn flask in 90minsLearn flask in 90mins
Learn flask in 90mins
Larry Cai
 
Flask
FlaskFlask
KISS Automation.py
KISS Automation.pyKISS Automation.py
KISS Automation.py
Iakiv Kramarenko
 
Flask patterns
Flask patternsFlask patterns
Flask patternsit-people
 
Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12
Michelangelo van Dam
 
PHPUnit: from zero to hero
PHPUnit: from zero to heroPHPUnit: from zero to hero
PHPUnit: from zero to hero
Jeremy Cook
 
Flask – Python
Flask – PythonFlask – Python
Flask – Python
Max Claus Nunes
 

What's hot (20)

Rest API using Flask & SqlAlchemy
Rest API using Flask & SqlAlchemyRest API using Flask & SqlAlchemy
Rest API using Flask & SqlAlchemy
 
Go swagger tutorial how to create golang api documentation using go swagger (1)
Go swagger tutorial how to create golang api documentation using go swagger (1)Go swagger tutorial how to create golang api documentation using go swagger (1)
Go swagger tutorial how to create golang api documentation using go swagger (1)
 
Php 7.2 compliance workshop php benelux
Php 7.2 compliance workshop php beneluxPhp 7.2 compliance workshop php benelux
Php 7.2 compliance workshop php benelux
 
Build restful ap is with python and flask
Build restful ap is with python and flaskBuild restful ap is with python and flask
Build restful ap is with python and flask
 
Developing Drizzle Replication Plugins
Developing Drizzle Replication PluginsDeveloping Drizzle Replication Plugins
Developing Drizzle Replication Plugins
 
3 introduction-php-mvc-cakephp-m3-getting-started-slides
3 introduction-php-mvc-cakephp-m3-getting-started-slides3 introduction-php-mvc-cakephp-m3-getting-started-slides
3 introduction-php-mvc-cakephp-m3-getting-started-slides
 
Flask Basics
Flask BasicsFlask Basics
Flask Basics
 
It's a Kind of Magic: Under the Covers of Spring Boot
It's a Kind of Magic: Under the Covers of Spring BootIt's a Kind of Magic: Under the Covers of Spring Boot
It's a Kind of Magic: Under the Covers of Spring Boot
 
Php Debugger
Php DebuggerPhp Debugger
Php Debugger
 
4 introduction-php-mvc-cakephp-m4-controllers-slides
4 introduction-php-mvc-cakephp-m4-controllers-slides4 introduction-php-mvc-cakephp-m4-controllers-slides
4 introduction-php-mvc-cakephp-m4-controllers-slides
 
React mit TypeScript – eine glückliche Ehe
React mit TypeScript – eine glückliche EheReact mit TypeScript – eine glückliche Ehe
React mit TypeScript – eine glückliche Ehe
 
Flask Introduction - Python Meetup
Flask Introduction - Python MeetupFlask Introduction - Python Meetup
Flask Introduction - Python Meetup
 
PHPUnit with CakePHP and Yii
PHPUnit with CakePHP and YiiPHPUnit with CakePHP and Yii
PHPUnit with CakePHP and Yii
 
Learn flask in 90mins
Learn flask in 90minsLearn flask in 90mins
Learn flask in 90mins
 
Flask
FlaskFlask
Flask
 
KISS Automation.py
KISS Automation.pyKISS Automation.py
KISS Automation.py
 
Flask patterns
Flask patternsFlask patterns
Flask patterns
 
Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12
 
PHPUnit: from zero to hero
PHPUnit: from zero to heroPHPUnit: from zero to hero
PHPUnit: from zero to hero
 
Flask – Python
Flask – PythonFlask – Python
Flask – Python
 

Similar to Weapons for Boilerplate Destruction

TYPO3 Extension development using new Extbase framework
TYPO3 Extension development using new Extbase frameworkTYPO3 Extension development using new Extbase framework
TYPO3 Extension development using new Extbase framework
Christian Trabold
 
"I have a framework idea" - Repeat less, share more.
"I have a framework idea" - Repeat less, share more."I have a framework idea" - Repeat less, share more.
"I have a framework idea" - Repeat less, share more.
Fabio Milano
 
Bring the fun back to java
Bring the fun back to javaBring the fun back to java
Bring the fun back to java
ciklum_ods
 
Fighting Fear-Driven-Development With PHPUnit
Fighting Fear-Driven-Development With PHPUnitFighting Fear-Driven-Development With PHPUnit
Fighting Fear-Driven-Development With PHPUnit
James Fuller
 
CICON2010: Adam Griffiths - CodeIgniter 2
CICON2010: Adam Griffiths - CodeIgniter 2CICON2010: Adam Griffiths - CodeIgniter 2
CICON2010: Adam Griffiths - CodeIgniter 2
CodeIgniter Conference
 
Simplify your professional web development with symfony
Simplify your professional web development with symfonySimplify your professional web development with symfony
Simplify your professional web development with symfony
Francois Zaninotto
 
Readme
ReadmeReadme
Readme
rec2006
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy Code
Rowan Merewood
 
What's New In Laravel 5
What's New In Laravel 5What's New In Laravel 5
What's New In Laravel 5
Darren Craig
 
Working With The Symfony Admin Generator
Working With The Symfony Admin GeneratorWorking With The Symfony Admin Generator
Working With The Symfony Admin Generator
John Cleveley
 
Save time by applying clean code principles
Save time by applying clean code principlesSave time by applying clean code principles
Save time by applying clean code principlesEdorian
 
From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)
Jose Manuel Pereira Garcia
 
The Beauty And The Beast Php N W09
The Beauty And The Beast Php N W09The Beauty And The Beast Php N W09
The Beauty And The Beast Php N W09
Bastian Feder
 
Gigigo Workshop - Create an iOS Framework, document it and not die trying
Gigigo Workshop - Create an iOS Framework, document it and not die tryingGigigo Workshop - Create an iOS Framework, document it and not die trying
Gigigo Workshop - Create an iOS Framework, document it and not die trying
Alex Rupérez
 
Oracle DBA interview_questions
Oracle DBA interview_questionsOracle DBA interview_questions
Oracle DBA interview_questions
Naveen P
 
Tml for Laravel
Tml for LaravelTml for Laravel
Tml for Laravel
Michael Berkovich
 
Refactoring
RefactoringRefactoring
Refactoring
Artem Tabalin
 
C:\Users\User\Desktop\Eclipse Infocenter
C:\Users\User\Desktop\Eclipse InfocenterC:\Users\User\Desktop\Eclipse Infocenter
C:\Users\User\Desktop\Eclipse InfocenterSuite Solutions
 
vJUG - The JavaFX Ecosystem
vJUG - The JavaFX EcosystemvJUG - The JavaFX Ecosystem
vJUG - The JavaFX Ecosystem
Andres Almiray
 

Similar to Weapons for Boilerplate Destruction (20)

TYPO3 Extension development using new Extbase framework
TYPO3 Extension development using new Extbase frameworkTYPO3 Extension development using new Extbase framework
TYPO3 Extension development using new Extbase framework
 
"I have a framework idea" - Repeat less, share more.
"I have a framework idea" - Repeat less, share more."I have a framework idea" - Repeat less, share more.
"I have a framework idea" - Repeat less, share more.
 
Bring the fun back to java
Bring the fun back to javaBring the fun back to java
Bring the fun back to java
 
Fighting Fear-Driven-Development With PHPUnit
Fighting Fear-Driven-Development With PHPUnitFighting Fear-Driven-Development With PHPUnit
Fighting Fear-Driven-Development With PHPUnit
 
CICON2010: Adam Griffiths - CodeIgniter 2
CICON2010: Adam Griffiths - CodeIgniter 2CICON2010: Adam Griffiths - CodeIgniter 2
CICON2010: Adam Griffiths - CodeIgniter 2
 
Simplify your professional web development with symfony
Simplify your professional web development with symfonySimplify your professional web development with symfony
Simplify your professional web development with symfony
 
Readme
ReadmeReadme
Readme
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy Code
 
What's New In Laravel 5
What's New In Laravel 5What's New In Laravel 5
What's New In Laravel 5
 
Working With The Symfony Admin Generator
Working With The Symfony Admin GeneratorWorking With The Symfony Admin Generator
Working With The Symfony Admin Generator
 
Save time by applying clean code principles
Save time by applying clean code principlesSave time by applying clean code principles
Save time by applying clean code principles
 
From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)
 
The Beauty And The Beast Php N W09
The Beauty And The Beast Php N W09The Beauty And The Beast Php N W09
The Beauty And The Beast Php N W09
 
Gigigo Workshop - Create an iOS Framework, document it and not die trying
Gigigo Workshop - Create an iOS Framework, document it and not die tryingGigigo Workshop - Create an iOS Framework, document it and not die trying
Gigigo Workshop - Create an iOS Framework, document it and not die trying
 
Oracle DBA interview_questions
Oracle DBA interview_questionsOracle DBA interview_questions
Oracle DBA interview_questions
 
Tml for Laravel
Tml for LaravelTml for Laravel
Tml for Laravel
 
Refactoring
RefactoringRefactoring
Refactoring
 
PhpSpec extension points
PhpSpec extension pointsPhpSpec extension points
PhpSpec extension points
 
C:\Users\User\Desktop\Eclipse Infocenter
C:\Users\User\Desktop\Eclipse InfocenterC:\Users\User\Desktop\Eclipse Infocenter
C:\Users\User\Desktop\Eclipse Infocenter
 
vJUG - The JavaFX Ecosystem
vJUG - The JavaFX EcosystemvJUG - The JavaFX Ecosystem
vJUG - The JavaFX Ecosystem
 

More from Everyware Technologies

The Professional Software Engineer
The Professional Software EngineerThe Professional Software Engineer
The Professional Software Engineer
Everyware Technologies
 
The Software Engineering process in Everyware Technologies
The Software Engineering process in Everyware TechnologiesThe Software Engineering process in Everyware Technologies
The Software Engineering process in Everyware Technologies
Everyware Technologies
 
New trends on research and software development techniques for wearable devices
New trends on research and software development techniques for wearable devicesNew trends on research and software development techniques for wearable devices
New trends on research and software development techniques for wearable devicesEveryware Technologies
 
Building TV apps with Chromecast
Building TV apps with ChromecastBuilding TV apps with Chromecast
Building TV apps with Chromecast
Everyware Technologies
 
From your pocket to your wrist with Android Wear
From your pocket to your wrist with Android WearFrom your pocket to your wrist with Android Wear
From your pocket to your wrist with Android Wear
Everyware Technologies
 
Building Glassware with the Glass Development Kit
Building Glassware with the Glass Development KitBuilding Glassware with the Glass Development Kit
Building Glassware with the Glass Development Kit
Everyware Technologies
 

More from Everyware Technologies (6)

The Professional Software Engineer
The Professional Software EngineerThe Professional Software Engineer
The Professional Software Engineer
 
The Software Engineering process in Everyware Technologies
The Software Engineering process in Everyware TechnologiesThe Software Engineering process in Everyware Technologies
The Software Engineering process in Everyware Technologies
 
New trends on research and software development techniques for wearable devices
New trends on research and software development techniques for wearable devicesNew trends on research and software development techniques for wearable devices
New trends on research and software development techniques for wearable devices
 
Building TV apps with Chromecast
Building TV apps with ChromecastBuilding TV apps with Chromecast
Building TV apps with Chromecast
 
From your pocket to your wrist with Android Wear
From your pocket to your wrist with Android WearFrom your pocket to your wrist with Android Wear
From your pocket to your wrist with Android Wear
 
Building Glassware with the Glass Development Kit
Building Glassware with the Glass Development KitBuilding Glassware with the Glass Development Kit
Building Glassware with the Glass Development Kit
 

Recently uploaded

Pro Unity Game Development with C-sharp Book
Pro Unity Game Development with C-sharp BookPro Unity Game Development with C-sharp Book
Pro Unity Game Development with C-sharp Book
abdulrafaychaudhry
 
Automated software refactoring with OpenRewrite and Generative AI.pptx.pdf
Automated software refactoring with OpenRewrite and Generative AI.pptx.pdfAutomated software refactoring with OpenRewrite and Generative AI.pptx.pdf
Automated software refactoring with OpenRewrite and Generative AI.pptx.pdf
timtebeek1
 
Large Language Models and the End of Programming
Large Language Models and the End of ProgrammingLarge Language Models and the End of Programming
Large Language Models and the End of Programming
Matt Welsh
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
Globus
 
OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024
OpenMetadata
 
Understanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSageUnderstanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSage
Globus
 
First Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User EndpointsFirst Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User Endpoints
Globus
 
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
Juraj Vysvader
 
Vitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdfVitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke
 
Top 7 Unique WhatsApp API Benefits | Saudi Arabia
Top 7 Unique WhatsApp API Benefits | Saudi ArabiaTop 7 Unique WhatsApp API Benefits | Saudi Arabia
Top 7 Unique WhatsApp API Benefits | Saudi Arabia
Yara Milbes
 
Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024
Paco van Beckhoven
 
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Globus
 
2024 RoOUG Security model for the cloud.pptx
2024 RoOUG Security model for the cloud.pptx2024 RoOUG Security model for the cloud.pptx
2024 RoOUG Security model for the cloud.pptx
Georgi Kodinov
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
Safe Software
 
Graspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code AnalysisGraspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code Analysis
Aftab Hussain
 
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing SuiteAI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
Google
 
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data AnalysisProviding Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Globus
 
Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"
Donna Lenk
 
Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604
Fermin Galan
 
May Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdfMay Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdf
Adele Miller
 

Recently uploaded (20)

Pro Unity Game Development with C-sharp Book
Pro Unity Game Development with C-sharp BookPro Unity Game Development with C-sharp Book
Pro Unity Game Development with C-sharp Book
 
Automated software refactoring with OpenRewrite and Generative AI.pptx.pdf
Automated software refactoring with OpenRewrite and Generative AI.pptx.pdfAutomated software refactoring with OpenRewrite and Generative AI.pptx.pdf
Automated software refactoring with OpenRewrite and Generative AI.pptx.pdf
 
Large Language Models and the End of Programming
Large Language Models and the End of ProgrammingLarge Language Models and the End of Programming
Large Language Models and the End of Programming
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
 
OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024OpenMetadata Community Meeting - 5th June 2024
OpenMetadata Community Meeting - 5th June 2024
 
Understanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSageUnderstanding Globus Data Transfers with NetSage
Understanding Globus Data Transfers with NetSage
 
First Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User EndpointsFirst Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User Endpoints
 
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
 
Vitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdfVitthal Shirke Java Microservices Resume.pdf
Vitthal Shirke Java Microservices Resume.pdf
 
Top 7 Unique WhatsApp API Benefits | Saudi Arabia
Top 7 Unique WhatsApp API Benefits | Saudi ArabiaTop 7 Unique WhatsApp API Benefits | Saudi Arabia
Top 7 Unique WhatsApp API Benefits | Saudi Arabia
 
Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024Cracking the code review at SpringIO 2024
Cracking the code review at SpringIO 2024
 
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
Exploring Innovations in Data Repository Solutions - Insights from the U.S. G...
 
2024 RoOUG Security model for the cloud.pptx
2024 RoOUG Security model for the cloud.pptx2024 RoOUG Security model for the cloud.pptx
2024 RoOUG Security model for the cloud.pptx
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
 
Graspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code AnalysisGraspan: A Big Data System for Big Code Analysis
Graspan: A Big Data System for Big Code Analysis
 
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing SuiteAI Pilot Review: The World’s First Virtual Assistant Marketing Suite
AI Pilot Review: The World’s First Virtual Assistant Marketing Suite
 
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data AnalysisProviding Globus Services to Users of JASMIN for Environmental Data Analysis
Providing Globus Services to Users of JASMIN for Environmental Data Analysis
 
Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"Navigating the Metaverse: A Journey into Virtual Evolution"
Navigating the Metaverse: A Journey into Virtual Evolution"
 
Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604Orion Context Broker introduction 20240604
Orion Context Broker introduction 20240604
 
May Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdfMay Marketo Masterclass, London MUG May 22 2024.pdf
May Marketo Masterclass, London MUG May 22 2024.pdf
 

Weapons for Boilerplate Destruction

  • 1. Weapons for Boilerplate DESTRUCTION Tomás Ruiz López Everyware Technologies Droidcon Spain 2015@tomasruizlopez tomas@everywaretech.es
  • 2. Tomás Ruiz-López Software Design Manager at Everyware Technologies @tomasruizlopez @everywaretech /everywaretech http://www.everywaretech.es WHO AM I? Postdoctoral Fellow at Cancer Registry of Norway Everyware Technologies tomas@everywaretech.es
  • 5.  public  class  MyParcelable  implements  Parcelable  {            private  int  mData;   !          public  int  describeContents()  {                    return  0;            }   !          public  void  writeToParcel(Parcel  out,  int  flags)  {                    out.writeInt(mData);            }   !          public  static  final  Parcelable.Creator<MyParcelable>  CREATOR                            =  new  Parcelable.Creator<MyParcelable>()  {                    public  MyParcelable  createFromParcel(Parcel  in)  {                            return  new  MyParcelable(in);                    }   !                  public  MyParcelable[]  newArray(int  size)  {                            return  new  MyParcelable[size];                    }            };                        private  MyParcelable(Parcel  in)  {                    mData  =  in.readInt();            }    }
  • 7. Postfix Completion Type expression ending in a dot Ctrl + Space 1 2 Choose:   field,  var,  cast,  instanceof,     not  null,  null,  par,  for,  fori,     …3
  • 15. Postfix Completion Quick typing Short completions Remember commands Not customizable
  • 16. Live Templates Type your shortcut keyword Expand with {Space | Tab | Enter} 1 2 Fill missing parts 3
  • 20. Live Templates Create Template Group or Live Template 1 Editable in Preferences  >  Live  Templates
  • 21. Live Templates Fill abbreviation, description and template code 2 Editable in Preferences  >  Live  Templates
  • 22. Live Templates Define applicability scope 3 Editable in Preferences  >  Live  Templates
  • 23. Live Templates Use it 4 Editable in Preferences  >  Live  Templates
  • 24. Live Templates Use it 4 Editable in Preferences  >  Live  Templates
  • 25. Live Templates Templates can be parameterized 2b Editable in Preferences  >  Live  Templates
  • 26. Live Templates Templates can be parameterized 2b Editable in Preferences  >  Live  Templates
  • 27. Live Templates Templates can be parameterized 2b Editable in Preferences  >  Live  Templates
  • 28. Live Templates Templates can be parameterized 2b Editable in Preferences  >  Live  Templates
  • 29. Live Templates Quick typing Short completions Remember commands Customizable (to some extent)
  • 34. file0..* Template Structure Template Folder root globals.xml.ftl1 recipe.xml.ftl1 template.xml1 icon.png0..* file.ftl0..* Global variables for the code generation Place it under ! <AndroidStudioPath>/plugins/android/lib/templates
  • 36. file0..* Template Structure Template Folder root globals.xml.ftl1 recipe.xml.ftl1 template.xml1 icon.png0..* file.ftl0..* Actions to perform when template is selected Place it under ! <AndroidStudioPath>/plugins/android/lib/templates
  • 38. file0..* Template Structure Template Folder root globals.xml.ftl1 recipe.xml.ftl1 template.xml1 icon.png0..* file.ftl0..*Icons to represent the template Place it under ! <AndroidStudioPath>/plugins/android/lib/templates
  • 40. file0..* Template Structure Template Folder root globals.xml.ftl1 recipe.xml.ftl1 template.xml1 icon.png0..* file.ftl0..* Files that just need to be copied Place it under ! <AndroidStudioPath>/plugins/android/lib/templates
  • 42. file0..* Template Structure Template Folder root globals.xml.ftl1 recipe.xml.ftl1 template.xml1 icon.png0..* file.ftl0..* Files that need to be filled with data Place it under ! <AndroidStudioPath>/plugins/android/lib/templates
  • 44. template.xml <template          format="4"          revision="1"          name="Retrofit  Service"          description="Creates  a  new  Retrofit  interface.">   !        <category  value="Everyware"  />   ! ...   ! </template>
  • 45. template.xml <parameter     id="className"     name="Interface  Name"     type="string"     constraints="class|unique|nonempty"     default="MyService"  /> <parameter     id="operationType"     name="Operation  Type"     type="enum"     constraints="nonempty"     default="get">                          <option  id="get">GET</option>     <option  id="post">POST</option>   </parameter>
  • 48. globals.xml.ftl <?xml  version="1.0"?>   <globals>          <global  id="manifestOut"  value="${manifestDir}"  />                ...   </globals>  
  • 49. globals.xml.ftl <?xml  version="1.0"?>   <globals>          <global  id="manifestOut"  value="${manifestDir}"  />                ...   </globals>   FreeMarker notation to access a variable
  • 50. globals.xml.ftl <?xml  version="1.0"?>   <globals>          <global  id="manifestOut"  value="${manifestDir}"  />                ...   </globals>  
  • 51. <?xml  version="1.0"?>   <recipe>               <dependency  mavenUrl="com.squareup.retrofit:retrofit:1.8.0"/>   ! !   <copy  from="res/values/urls.xml"                    to=“${resOut}/values/urls.xml"  />   ! !   <instantiate  from="src/app_package/Service.java.ftl"                          to="${srcOut}/${className}.java"  />   !             <open  file="${srcOut}/${className}.java"  />   !           </recipe> recipe.xml.ftl
  • 52. <?xml  version="1.0"?>   <recipe>               <dependency  mavenUrl="com.squareup.retrofit:retrofit:1.8.0"/>   ! !   <copy  from="res/values/urls.xml"                    to=“${resOut}/values/urls.xml"  />   ! !   <instantiate  from="src/app_package/Service.java.ftl"                          to="${srcOut}/${className}.java"  />   !             <open  file="${srcOut}/${className}.java"  />   !           </recipe> recipe.xml.ftl Adds a provided dependency to build.gradle
  • 53. <?xml  version="1.0"?>   <recipe>               <dependency  mavenUrl="com.squareup.retrofit:retrofit:1.8.0"/>   ! !   <copy  from="res/values/urls.xml"                    to=“${resOut}/values/urls.xml"  />   ! !   <instantiate  from="src/app_package/Service.java.ftl"                          to="${srcOut}/${className}.java"  />   !             <open  file="${srcOut}/${className}.java"  />   !           </recipe> recipe.xml.ftl
  • 54. <?xml  version="1.0"?>   <recipe>               <dependency  mavenUrl="com.squareup.retrofit:retrofit:1.8.0"/>   ! !   <copy  from="res/values/urls.xml"                    to=“${resOut}/values/urls.xml"  />   ! !   <instantiate  from="src/app_package/Service.java.ftl"                          to="${srcOut}/${className}.java"  />   !             <open  file="${srcOut}/${className}.java"  />   !           </recipe> recipe.xml.ftl Copies a file without processing
  • 55. <?xml  version="1.0"?>   <recipe>               <dependency  mavenUrl="com.squareup.retrofit:retrofit:1.8.0"/>   ! !   <copy  from="res/values/urls.xml"                    to=“${resOut}/values/urls.xml"  />   ! !   <instantiate  from="src/app_package/Service.java.ftl"                          to="${srcOut}/${className}.java"  />   !             <open  file="${srcOut}/${className}.java"  />   !           </recipe> recipe.xml.ftl
  • 56. <?xml  version="1.0"?>   <recipe>               <dependency  mavenUrl="com.squareup.retrofit:retrofit:1.8.0"/>   ! !   <copy  from="res/values/urls.xml"                    to=“${resOut}/values/urls.xml"  />   ! !   <instantiate  from="src/app_package/Service.java.ftl"                          to="${srcOut}/${className}.java"  />   !             <open  file="${srcOut}/${className}.java"  />   !           </recipe> recipe.xml.ftl Generates a file from a template and the provided parameters
  • 57. <?xml  version="1.0"?>   <recipe>               <dependency  mavenUrl="com.squareup.retrofit:retrofit:1.8.0"/>   ! !   <copy  from="res/values/urls.xml"                    to=“${resOut}/values/urls.xml"  />   ! !   <instantiate  from="src/app_package/Service.java.ftl"                          to="${srcOut}/${className}.java"  />   !             <open  file="${srcOut}/${className}.java"  />   !           </recipe> recipe.xml.ftl
  • 58. <?xml  version="1.0"?>   <recipe>               <dependency  mavenUrl="com.squareup.retrofit:retrofit:1.8.0"/>   ! !   <copy  from="res/values/urls.xml"                    to=“${resOut}/values/urls.xml"  />   ! !   <instantiate  from="src/app_package/Service.java.ftl"                          to="${srcOut}/${className}.java"  />   !             <open  file="${srcOut}/${className}.java"  />   !           </recipe> recipe.xml.ftl Opens a file in the IDE
  • 59. <?xml  version="1.0"?>   <recipe>               <dependency  mavenUrl="com.squareup.retrofit:retrofit:1.8.0"/>   ! !   <copy  from="res/values/urls.xml"                    to=“${resOut}/values/urls.xml"  />   ! !   <instantiate  from="src/app_package/Service.java.ftl"                          to="${srcOut}/${className}.java"  />   !             <open  file="${srcOut}/${className}.java"  />   !           </recipe> recipe.xml.ftl
  • 60. <?xml  version="1.0"?>   <recipe>               <dependency  mavenUrl="com.squareup.retrofit:retrofit:1.8.0"/>   ! !   <copy  from="res/values/urls.xml"                    to=“${resOut}/values/urls.xml"  />   ! !   <instantiate  from="src/app_package/Service.java.ftl"                          to="${srcOut}/${className}.java"  />   !             <open  file="${srcOut}/${className}.java"  />   !           </recipe> recipe.xml.ftl PRO TIP: Put an open command at the end of your recipe to make sure everything executed correctly
  • 61. <?xml  version="1.0"?>   <recipe>               <dependency  mavenUrl="com.squareup.retrofit:retrofit:1.8.0"/>   ! !   <copy  from="res/values/urls.xml"                    to=“${resOut}/values/urls.xml"  />   ! !   <instantiate  from="src/app_package/Service.java.ftl"                          to="${srcOut}/${className}.java"  />   !             <open  file="${srcOut}/${className}.java"  />   !           </recipe> recipe.xml.ftl
  • 62. Service.java.ftl package  ${packageName};   ! <@imports/>   ! public  interface  ${className}{                    <@multipart/>          <@operation/>          <@methodSignature/>             } <#macro  imports>   <#if  operationType="get">   import  retrofit.http.GET;   <#else/>   import  retrofit.http.POST;   </#if>   ...   </#macro> <#macro  methodSignature>          public  <@output/>  ${methodName}(<@methodParameters/>);   </#macro>
  • 63. ADT Templates Generates multiple files, even projects Customizable Only for creation Automatic UI wizard generated Complex syntax Difficult to test and verify correctness
  • 65. apply  plugin:  SimplePlugin   ! class  SimplePlugin  implements  Plugin<Project>  {          void  apply(Project  project)  {   !                println  "Hello  World!"   !        }   } Gradle Plugin
  • 66. apply  plugin:  SimplePlugin   ! class  SimplePlugin  implements  Plugin<Project>  {          void  apply(Project  project)  {   !     def  hasApp  =  project.plugins.withType(AppPlugin)       def  hasLib  =  project.plugins.withType(LibraryPlugin)       if  (!hasApp  &&  !hasLib)  {         throw  new  IllegalStateException("'android'  or  'android-­‐ library'  plugin  required.")       }   !        }   } Checking Android plugin dependencies
  • 67. Adding dependencies apply  plugin:  SimplePlugin   ! class  SimplePlugin  implements  Plugin<Project>  {          void  apply(Project  project)  {   !     project.dependencies  {         debugCompile  'your-­‐dependency'         compile  'your-­‐dependency'       }   !        }   }
  • 68. apply  plugin:  SimplePlugin   ! class  SimplePlugin  implements  Plugin<Project>  {          void  apply(Project  project)  {   !     project.extensions.create('myextension',                          SimpleExtension)   !        }   }   ! class  SimpleExtension  {     int  aNumber  =  0     List<String>  aList  =  []   } Adding extensions
  • 69. Adding extensions apply  plugin:  'com.android.application'   apply  plugin:  SimplePlugin   ! android  {          compileSdkVersion  21          buildToolsVersion  "21.1.2"   !        defaultConfig  {                  applicationId  "es.everywaretech.myapplication"                  minSdkVersion  15                  targetSdkVersion  21                  versionCode  1                  versionName  "1.0"          }   }   ...   myextension{     aNumber  =  42     aList  =  ["Hello",  "World"]   }
  • 70. Iterating through Variants apply  plugin:  SimplePlugin   ! class  SimplePlugin  implements  Plugin<Project>  {          void  apply(Project  project)  {   !     variants.all  {  variant  -­‐>         if  (!variant.buildType.isDebuggable())  {           //  Do  something  with  Debug  variant         }else{           //  Do  something  with  Release  variant         }       }   !        }   }
  • 71. Creating custom tasks class  SimpleTask  extends  DefaultTask  {          String  greeting  =  'Hello  World'   !        @TaskAction          def  greet()  {                  println  greeting          }   }   ! //  Use  the  default  task   task  hello(type:  SimpleTask)   ! //  Customize  the  task   task  droidcon(type:  SimpleTask)  {          greeting  =  'Hello  Droidcon'   }
  • 72. Creating custom incremental tasks class  MyIncrementalTask  extends  DefaultTask  {          @InputDirectory          def  File  inputDir   !        @OutputDirectory          def  File  outputDir   !        @Input          def  inputProperty   !        @TaskAction          void  execute(IncrementalTaskInputs  inputs)  {         if(inputs.incremental){           //  Only  changed  files  will  be  provided         }else{           //  All  files  will  be  provided         }                   ...          }   } Warning! Incubating feature
  • 73. Creating custom incremental tasks class  MyIncrementalTask  extends  DefaultTask  {          ...   !        @TaskAction          void  execute(IncrementalTaskInputs  inputs)  {          ...                  inputs.outOfDate  {  change  -­‐>                        //  Do  something                  }   !                inputs.removed  {  change  -­‐>                        //  Do  something                  }          }   } Warning! Incubating feature
  • 74. Gradle Plugins Helps with recurring building tasks Not only for source code, also other resources Only available at build time
  • 76. Using annotations @Nullable   @Override   public  View  onCreateView(String  name,                      @NonNull  Context  context,                      @NonNull  AttributeSet  attrs)  {     ...   }  
  • 77. Using annotations @Nullable   @Override   public  View  onCreateView(String  name,                      @NonNull  Context  context,                      @NonNull  AttributeSet  attrs)  {     ...   }   PRO TIP: Use Support Annotations ! dependencies  {          compile  'com.android.support:support-­‐annotations:20.0.0'   }
  • 78. Using annotations @Nullable   @Override   public  View  onCreateView(String  name,                      @NonNull  Context  context,                      @NonNull  AttributeSet  attrs)  {     ...   }  
  • 79. Defining annotations types @Retention(Retention.{SOURCE|CLASS|RUNTIME})   @Target(ElementType.{ANNOTATION_TYPE|CONSTRUCTOR|FIELD|                  LOCAL_VARIABLE|METHOD|PACKAGE|                  PARAMETER|TYPE})   public  @interface  MyAnnotation{     String  value()  default  "some  string";     int  number()  default  0;   }   ! @MyAnnotation("another  string",  number  =  42)   public  class  MyClass{     ...   }
  • 80. Processing annotations public  interface  Processor{   !   Iterable<?  extends  Completion>  getCompletions(Element  element,       AnnotationMirror  annotation,         ExecutableElement  member,         String  userText);   !   Set<String>  getSupportedAnnotationTypes();   !   Set<String>  getSupportedOptions();   !   SourceVersion  getSupportedSourceVersion();   !   void  init(ProcessingEnvironment  processingEnv);   !   boolean  process(Set<?  extends  TypeElement>  annotations,         RoundEnvironment  roundEnv);   ! }
  • 81. Processing annotations public  interface  Processor{   !   Iterable<?  extends  Completion>  getCompletions(Element  element,       AnnotationMirror  annotation,         ExecutableElement  member,         String  userText);   !   Set<String>  getSupportedAnnotationTypes();   !   Set<String>  getSupportedOptions();   !   SourceVersion  getSupportedSourceVersion();   !   void  init(ProcessingEnvironment  processingEnv);   !   boolean  process(Set<?  extends  TypeElement>  annotations,         RoundEnvironment  roundEnv);   ! } Suggestions for the IDE to complete an annotation
  • 82. Processing annotations public  interface  Processor{   !   Iterable<?  extends  Completion>  getCompletions(Element  element,       AnnotationMirror  annotation,         ExecutableElement  member,         String  userText);   !   Set<String>  getSupportedAnnotationTypes();   !   Set<String>  getSupportedOptions();   !   SourceVersion  getSupportedSourceVersion();   !   void  init(ProcessingEnvironment  processingEnv);   !   boolean  process(Set<?  extends  TypeElement>  annotations,         RoundEnvironment  roundEnv);   ! }
  • 83. Processing annotations public  interface  Processor{   !   Iterable<?  extends  Completion>  getCompletions(Element  element,       AnnotationMirror  annotation,         ExecutableElement  member,         String  userText);   !   Set<String>  getSupportedAnnotationTypes();   !   Set<String>  getSupportedOptions();   !   SourceVersion  getSupportedSourceVersion();   !   void  init(ProcessingEnvironment  processingEnv);   !   boolean  process(Set<?  extends  TypeElement>  annotations,         RoundEnvironment  roundEnv);   ! } Annotations that this Processor is able to handle
  • 84. Processing annotations public  interface  Processor{   !   Iterable<?  extends  Completion>  getCompletions(Element  element,       AnnotationMirror  annotation,         ExecutableElement  member,         String  userText);   !   Set<String>  getSupportedAnnotationTypes();   !   Set<String>  getSupportedOptions();   !   SourceVersion  getSupportedSourceVersion();   !   void  init(ProcessingEnvironment  processingEnv);   !   boolean  process(Set<?  extends  TypeElement>  annotations,         RoundEnvironment  roundEnv);   ! }
  • 85. Processing annotations public  interface  Processor{   !   Iterable<?  extends  Completion>  getCompletions(Element  element,       AnnotationMirror  annotation,         ExecutableElement  member,         String  userText);   !   Set<String>  getSupportedAnnotationTypes();   !   Set<String>  getSupportedOptions();   !   SourceVersion  getSupportedSourceVersion();   !   void  init(ProcessingEnvironment  processingEnv);   !   boolean  process(Set<?  extends  TypeElement>  annotations,         RoundEnvironment  roundEnv);   ! } Processor initialization
  • 86. Processing annotations public  interface  Processor{   !   Iterable<?  extends  Completion>  getCompletions(Element  element,       AnnotationMirror  annotation,         ExecutableElement  member,         String  userText);   !   Set<String>  getSupportedAnnotationTypes();   !   Set<String>  getSupportedOptions();   !   SourceVersion  getSupportedSourceVersion();   !   void  init(ProcessingEnvironment  processingEnv);   !   boolean  process(Set<?  extends  TypeElement>  annotations,         RoundEnvironment  roundEnv);   ! }
  • 87. Processing annotations public  interface  Processor{   !   Iterable<?  extends  Completion>  getCompletions(Element  element,       AnnotationMirror  annotation,         ExecutableElement  member,         String  userText);   !   Set<String>  getSupportedAnnotationTypes();   !   Set<String>  getSupportedOptions();   !   SourceVersion  getSupportedSourceVersion();   !   void  init(ProcessingEnvironment  processingEnv);   !   boolean  process(Set<?  extends  TypeElement>  annotations,         RoundEnvironment  roundEnv);   ! } Inspection of the annotations and code generation
  • 88. Processing annotations public  interface  Processor{   !   Iterable<?  extends  Completion>  getCompletions(Element  element,       AnnotationMirror  annotation,         ExecutableElement  member,         String  userText);   !   Set<String>  getSupportedAnnotationTypes();   !   Set<String>  getSupportedOptions();   !   SourceVersion  getSupportedSourceVersion();   !   void  init(ProcessingEnvironment  processingEnv);   !   boolean  process(Set<?  extends  TypeElement>  annotations,         RoundEnvironment  roundEnv);   ! }
  • 89. Processing annotations public  interface  ProcessingEnvironment{         Elements  getElementUtils();   !   Filer  getFiler();   !   Locale  getLocale();   !   Messager  getMessager();   !   Map<String,String>  getOptions();   !   SourceVersion  getSourceVersion();   !   Types  getTypeUtils();   }
  • 90. Processing annotations public  interface  ProcessingEnvironment{         Elements  getElementUtils();   !   Filer  getFiler();   !   Locale  getLocale();   !   Messager  getMessager();   !   Map<String,String>  getOptions();   !   SourceVersion  getSourceVersion();   !   Types  getTypeUtils();   } Creation of new Files
  • 91. Processing annotations public  interface  ProcessingEnvironment{         Elements  getElementUtils();   !   Filer  getFiler();   !   Locale  getLocale();   !   Messager  getMessager();   !   Map<String,String>  getOptions();   !   SourceVersion  getSourceVersion();   !   Types  getTypeUtils();   }
  • 92. Processing annotations public  interface  ProcessingEnvironment{         Elements  getElementUtils();   !   Filer  getFiler();   !   Locale  getLocale();   !   Messager  getMessager();   !   Map<String,String>  getOptions();   !   SourceVersion  getSourceVersion();   !   Types  getTypeUtils();   } Writing warnings and errors
  • 93. Processing annotations public  interface  ProcessingEnvironment{         Elements  getElementUtils();   !   Filer  getFiler();   !   Locale  getLocale();   !   Messager  getMessager();   !   Map<String,String>  getOptions();   !   SourceVersion  getSourceVersion();   !   Types  getTypeUtils();   }
  • 94. Processing annotations @AutoService(Processor.class)   public  class  MyProcessor{   !   @Override  public  Set<String>  getSupportedAnnotationTypes(){       return  Collections.singleton(MyAnnotation.class.getName());     }   !   @Override  public  SourceVersion  getSupportedSourceVersion(){       return  SourceVersion.latestSupported();     }   !   @Override  public  boolean  process(Set<?  extends  TypeElement>   annotations,  RoundEnvironment  roundEnv){   !     Set<?  extends  Element>  elements           =  roundEnv.getElementsAnnotatedWith(MyAnnotation.class);       //  Process  elements  and  generate  code   !     return  false;     }   }
  • 95. Processing annotations @AutoService(Processor.class)   public  class  MyProcessor{   !   @Override  public  Set<String>  getSupportedAnnotationTypes(){       return  Collections.singleton(MyAnnotation.class.getName());     }   !   @Override  public  SourceVersion  getSupportedSourceVersion(){       return  SourceVersion.latestSupported();     }   !   @Override  public  boolean  process(Set<?  extends  TypeElement>   annotations,  RoundEnvironment  roundEnv){   !     Set<?  extends  Element>  elements           =  roundEnv.getElementsAnnotatedWith(MyAnnotation.class);       //  Process  elements  and  generate  code   !     return  false;     }   } PRO TIP: Use com.squareup.JavaPoet to generate code
  • 96. Processing annotations @AutoService(Processor.class)   public  class  MyProcessor{   !   @Override  public  Set<String>  getSupportedAnnotationTypes(){       return  Collections.singleton(MyAnnotation.class.getName());     }   !   @Override  public  SourceVersion  getSupportedSourceVersion(){       return  SourceVersion.latestSupported();     }   !   @Override  public  boolean  process(Set<?  extends  TypeElement>   annotations,  RoundEnvironment  roundEnv){   !     Set<?  extends  Element>  elements           =  roundEnv.getElementsAnnotatedWith(MyAnnotation.class);       //  Process  elements  and  generate  code   !     return  false;     }   }
  • 97. Processing annotations @AutoService(Processor.class)   public  class  MyProcessor{   !   @Override  public  Set<String>  getSupportedAnnotationTypes(){       return  Collections.singleton(MyAnnotation.class.getName());     }   !   @Override  public  SourceVersion  getSupportedSourceVersion(){       return  SourceVersion.latestSupported();     }   !   @Override  public  boolean  process(Set<?  extends  TypeElement>   annotations,  RoundEnvironment  roundEnv){   !     Set<?  extends  Element>  elements           =  roundEnv.getElementsAnnotatedWith(MyAnnotation.class);       //  Process  elements  and  generate  code   !     return  false;     }   } Allows other processors to handle the same annotations
  • 98. Processing annotations @AutoService(Processor.class)   public  class  MyProcessor{   !   @Override  public  Set<String>  getSupportedAnnotationTypes(){       return  Collections.singleton(MyAnnotation.class.getName());     }   !   @Override  public  SourceVersion  getSupportedSourceVersion(){       return  SourceVersion.latestSupported();     }   !   @Override  public  boolean  process(Set<?  extends  TypeElement>   annotations,  RoundEnvironment  roundEnv){   !     Set<?  extends  Element>  elements           =  roundEnv.getElementsAnnotatedWith(MyAnnotation.class);       //  Process  elements  and  generate  code   !     return  false;     }   }
  • 99. Processing annotations @AutoService(Processor.class)   public  class  MyProcessor{   !   @Override  public  Set<String>  getSupportedAnnotationTypes(){       return  Collections.singleton(MyAnnotation.class.getName());     }   !   @Override  public  SourceVersion  getSupportedSourceVersion(){       return  SourceVersion.latestSupported();     }   !   @Override  public  boolean  process(Set<?  extends  TypeElement>   annotations,  RoundEnvironment  roundEnv){   !     Set<?  extends  Element>  elements           =  roundEnv.getElementsAnnotatedWith(MyAnnotation.class);       //  Process  elements  and  generate  code   !     return  false;     }   } PRO TIP: Use AutoService to generate META-INF
  • 100. Processing annotations @AutoService(Processor.class)   public  class  MyProcessor{   !   @Override  public  Set<String>  getSupportedAnnotationTypes(){       return  Collections.singleton(MyAnnotation.class.getName());     }   !   @Override  public  SourceVersion  getSupportedSourceVersion(){       return  SourceVersion.latestSupported();     }   !   @Override  public  boolean  process(Set<?  extends  TypeElement>   annotations,  RoundEnvironment  roundEnv){   !     Set<?  extends  Element>  elements           =  roundEnv.getElementsAnnotatedWith(MyAnnotation.class);       //  Process  elements  and  generate  code   !     return  false;     }   }
  • 108. Annotation Processors Java feature, IDE independent Not only for source code, also other resources Expensive if done at runtime Testable
  • 110. Extending AnAction public  class  MyAction  extends  AnAction  {     @Override     public  void  actionPerformed(AnActionEvent  e)  {   !   }   }  
  • 111. Retrieve the selected element public  class  MyAction  extends  AnAction  {     @Override     public  void  actionPerformed(AnActionEvent  e)  {   !     PsiFile  psiFile  =  e.getData(LangDataKeys.PSI_FILE);       Editor  editor  =  e.getData(PlatformDataKeys.EDITOR);   !     if  (psiFile  ==  null  ||  editor  ==  null)  {         return;       }   !     int  offset  =  editor.getCaretModel().getOffset();       PsiElement  element  =  psiFile.findElementAt(offset);   !   }   }  
  • 112. Retrieve the selected class public  class  MyAction  extends  AnAction  {     @Override     public  void  actionPerformed(AnActionEvent  e)  {   !     PsiFile  psiFile  =  e.getData(LangDataKeys.PSI_FILE);       Editor  editor  =  e.getData(PlatformDataKeys.EDITOR);   !     if  (psiFile  ==  null  ||  editor  ==  null)  {         return;       }   !     int  offset  =  editor.getCaretModel().getOffset();       PsiElement  element  =  psiFile.findElementAt(offset);   !     PsiClass  psiClass  =  PsiTreeUtil.getParentOfType(element,   PsiClass.class);   !   }   }  
  • 113. Generate code public  class  MyAction  extends  AnAction  {     @Override     public  void  actionPerformed(AnActionEvent  e)  {   !     ...   !     new  WriteCommandAction.Simple(psiClass.getProject(),   psiClass.getContainingFile())  {         @Override         protected  void  run()  throws  Throwable  {           generateCode(psiClass);         }       }.execute();     }   }  
  • 114. Generate code public  void  generateCode(PsiClass  psiClass){     PsiElementFactory  elementFactory  =         JavaPsiFacade.getElementFactory(psiClass.getProject());   !   PsiMethod  myMethod  =         elementFactory.createMethodFromText(methodCode,  psiClass);   !   PsiField  myField  =       elementFactory.createFieldFromText(fieldCode,  psiClass);   !   ...   }
  • 115. Generate code public  void  generateCode(PsiClass  psiClass){     ...   !   JavaCodeStyleManager  styleManager  =         JavaCodeStyleManager.getInstance(psiClass.getProject());   !   styleManager.shortenClassReferences(       psiClass.addBefore(myMethod,  psiClass.getLastChild()));   !   styleManager.shortenClassReferences(       psiClass.addBefore(myField,  psiClass.getLastChild()));   }
  • 116. Register action <idea-­‐plugin  version="4">     <id>com.example.myplugin</id>     <name>Droidcon  Plugin</name>     <version>1.0</version>     <vendor  email="tomas@everywaretech.es"            url="http://www.everywaretech.es">       Tomás  Ruiz-­‐López     </vendor>   !   <actions>       <action  id="myplugin"           class="es.everywaretech.myplugin"         text="MyPlugin"         description="Generates  Boilerplate  Code">   !       <add-­‐to-­‐group  group-­‐id="MainMenu"  anchor="last"/>       </action>     </actions>   </idea-­‐plugin>   plugin.xml
  • 117. Register action <idea-­‐plugin  version="4">     <id>com.example.myplugin</id>     <name>Droidcon  Plugin</name>     <version>1.0</version>     <vendor  email="tomas@everywaretech.es"            url="http://www.everywaretech.es">       Tomás  Ruiz-­‐López     </vendor>   !   <actions>       <action  id="myplugin"           class="es.everywaretech.myplugin"         text="MyPlugin"         description="Generates  Boilerplate  Code">   !       <add-­‐to-­‐group  group-­‐id="MainMenu"  anchor="last"/>       </action>     </actions>   </idea-­‐plugin>   See com.intellij.openapi.actionSystem.ActionPlaces   for more group ids plugin.xml
  • 118. Register action <idea-­‐plugin  version="4">     <id>com.example.myplugin</id>     <name>Droidcon  Plugin</name>     <version>1.0</version>     <vendor  email="tomas@everywaretech.es"            url="http://www.everywaretech.es">       Tomás  Ruiz-­‐López     </vendor>   !   <actions>       <action  id="myplugin"           class="es.everywaretech.myplugin"         text="MyPlugin"         description="Generates  Boilerplate  Code">   !       <add-­‐to-­‐group  group-­‐id="MainMenu"  anchor="last"/>       </action>     </actions>   </idea-­‐plugin>   plugin.xml
  • 119. IDE Plugins More flexible Fine and coarse grained code generation More complex to develop Only for IntelliJ or Android Studio
  • 121. About ADT Templates Official documentation https://android.googlesource.com/platform/sdk/+/refs/heads/master/templates/docs/index.html About Gradle Plugins Writing Custom Plugins https://gradle.org/docs/current/userguide/custom_plugins.html ! Lessons learned from our first Gradle plugin for Android, Victor https://trello.engineering/victor/ ! Hugo https://github.com/JakeWharton/hugo
  • 122. About Annotation Processors Annotation Processing Boilerplate Destruction https://speakerdeck.com/jakewharton/annotation-processing-boilerplate-destruction-droidcon-nyc-2014 About IntelliJ Plugins Getting Started with Plugin Development https://confluence.jetbrains.com/display/IDEADEV/Getting+Started+with+Plugin+Development !
  • 123. Thanks! QUESTIONS? Tomás Ruiz López Everyware Technologies Droidcon Spain 2015@tomasruizlopez tomas@everywaretech.es