SlideShare una empresa de Scribd logo
1 de 123
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

Más contenido relacionado

La actualidad más candente

Rest API using Flask & SqlAlchemy
Rest API using Flask & SqlAlchemyRest API using Flask & SqlAlchemy
Rest API using Flask & SqlAlchemyAlessandro 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 beneluxDamien 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 flaskJeetendra singh
 
Developing Drizzle Replication Plugins
Developing Drizzle Replication PluginsDeveloping Drizzle Replication Plugins
Developing Drizzle Replication PluginsPadraig 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
 
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 BootVMware Tanzu
 
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 Eheinovex GmbH
 
Flask Introduction - Python Meetup
Flask Introduction - Python MeetupFlask Introduction - Python Meetup
Flask Introduction - Python MeetupAreski Belaid
 
PHPUnit with CakePHP and Yii
PHPUnit with CakePHP and YiiPHPUnit with CakePHP and Yii
PHPUnit with CakePHP and Yiimadhavi Ghadge
 
Learn flask in 90mins
Learn flask in 90minsLearn flask in 90mins
Learn flask in 90minsLarry Cai
 
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 tek12Michelangelo van Dam
 
PHPUnit: from zero to hero
PHPUnit: from zero to heroPHPUnit: from zero to hero
PHPUnit: from zero to heroJeremy Cook
 

La actualidad más candente (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 a 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 frameworkChristian 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 javaciklum_ods
 
Fighting Fear-Driven-Development With PHPUnit
Fighting Fear-Driven-Development With PHPUnitFighting Fear-Driven-Development With PHPUnit
Fighting Fear-Driven-Development With PHPUnitJames Fuller
 
CICON2010: Adam Griffiths - CodeIgniter 2
CICON2010: Adam Griffiths - CodeIgniter 2CICON2010: Adam Griffiths - CodeIgniter 2
CICON2010: Adam Griffiths - CodeIgniter 2CodeIgniter 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 symfonyFrancois Zaninotto
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy CodeRowan Merewood
 
What's New In Laravel 5
What's New In Laravel 5What's New In Laravel 5
What's New In Laravel 5Darren Craig
 
Working With The Symfony Admin Generator
Working With The Symfony Admin GeneratorWorking With The Symfony Admin Generator
Working With The Symfony Admin GeneratorJohn 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 W09Bastian 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 tryingAlex Rupérez
 
Oracle DBA interview_questions
Oracle DBA interview_questionsOracle DBA interview_questions
Oracle DBA interview_questionsNaveen P
 
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 EcosystemAndres Almiray
 

Similar a 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
 

Más de 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 TechnologiesEveryware 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
 
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 WearEveryware 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 KitEveryware Technologies
 

Más de 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
 

Último

WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisamasabamasaba
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnAmarnathKambale
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension AidPhilip Schwarz
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsArshad QA
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesVictorSzoltysek
 
tonesoftg
tonesoftgtonesoftg
tonesoftglanshi9
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyviewmasabamasaba
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...masabamasaba
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park masabamasaba
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrainmasabamasaba
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareJim McKeeth
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...masabamasaba
 
%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in sowetomasabamasaba
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...masabamasaba
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdfPearlKirahMaeRagusta1
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...SelfMade bd
 

Último (20)

WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
tonesoftg
tonesoftgtonesoftg
tonesoftg
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 

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