Consider the following servlet code:
public class AddDevice extends JsonServlet {
private static final long serialVersionUID = 1L;
#Override
protected void doGet(final JsonServletRequest request,
final JsonServletResponse response) throws ServletException,
IOException {
try {
final DeviceEntity device = new DeviceEntity();
device.type =
FleetManagerDatabaseHelper
.deviceTypesAccessor()
.queryForId(Integer.valueOf(
request.getParameter(DeviceTypeEntity._ID)));
device.sn = request.getParameter(DeviceEntity._SN);
device.status = Long.valueOf(0);
FleetManagerDatabaseHelper.devicesAccessor().create(device);
}
catch (final SQLException e) {
throw new ServletException("device already exists");
}
}
}
This code depends on the DeviceEntity and on the FleetManagerDatabaseHelper classes.
Now, I would like to write a test for it checking that the created entity is filled with the correct type, sn and status values.
For this purpose I could create a FleetManagerDatabaseHelperMockup class.
How would you apply Google Guice (or something else) here with minimal changes?
Your first step is to design for dependency injection--avoid constructors and static methods, and instead take in instances that you require. It looks like those types are Provider<DeviceEntity>, DevicesAccessor, and DeviceTypesAccessor.
Provider is a very simple Guice interface that provides instances of whatever class is in its type argument via a single no-arg method get(). If you have bound Foo, Guice automatically knows how to bind Provider<Foo>. It is extremely useful if your instances are expensive, or if you need more than one over the lifetime of your servlet (as you do).
After refactoring for dependency injection, your class will look like this:
public class AddDevice extends JsonServlet {
private static final long serialVersionUID = 1L;
private final Provider<DeviceEntity> deviceEntityProvider;
private final DevicesAccessor devicesAccessor;
private final DeviceTypesAccessor deviceTypesAccessor;
#Inject
public AddDevice(Provider<DeviceEntity> deviceEntityProvider,
DevicesAccessor devicesAccessor,
DeviceTypesAccessor deviceTypesAccessor>) {
this.deviceEntityProvider = deviceEntityProvider;
this.devicesAccessor = devicesAccessor;
this.deviceTypesAccessor = deviceTypesAccessor;
}
#Override
protected void doGet(final JsonServletRequest request,
final JsonServletResponse response) throws ServletException,
IOException {
try {
final DeviceEntity device = deviceEntityProvider.get();
device.type = deviceTypesAccessor.queryForId(
Integer.valueOf(request.getParameter(DeviceTypeEntity._ID)));
device.sn = request.getParameter(DeviceEntity._SN)
device.status = Long.valueOf(0);
devicesAccessor.create(device);
} catch (final SQLException e) {
throw new ServletException("device already exists");
}
}
}
At this point, it's extremely easy to write a test by passing in a Provider that keeps track of the instance it returns, along with a mock DevicesAccessor and a mock DeviceTypesAccessor. (I recommend Mockito.) If you write your own Provider interface and remove the #Inject, you don't even need to use Guice; in your tests, you could continue to use that constructor, but you would want to satisfy Java EE with a constructor like:
public AddDevice() {
this(new NewDeviceEntityProvider(),
FleetManagerDatabaseHelper.deviceTypesAccessor(),
FleetManagerDatabaseHelper.devicesAccessor());
}
private class NewDeviceEntityProvider implements Provider<DeviceEntity> {
#Override public DeviceEntity get() {
return new DeviceEntity();
}
}
But if you do want to use Guice to remove that boilerplate, just write a Guice Module. Your module would need to bind DeviceTypesAccessor and DevicesAccessor to the instances that FleetManagerDatabaseHelper would return; Guice would see that DeviceEntity has a no-arg constructor and would be able to inject DeviceEntity and Provider<DeviceEntity> automatically. (Comment if you want me to expand on what the Module would look like.)
Hope this helps!
Related
I'm working on the reporting module of our web-application. There are six reports available to the client, each of them has a code. The problem is that now the module is not closed for modification with respect to potential addition of new reports, thus violating OCP.
To elucidate, I have the following set of classes:
A generic report class, which all other reports inherit:
public abstract class Report
{
private final String code;
Report(String code)
{
this.code = code;
}
public String getCode() { return code; }
public abstract byte[] generate();
}
A servlet which manages POST requests for report generation:
public class ReportServlet extends HttpServlet
{
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
Report requested = ReportRegistry.lookup(req.getParameter("report_code"));
byte[] bytes = requested.generate();
// attach bytes to response
}
}
Report registry, which stores all existing reports for later access:
public class ReportRegistry
{
private static final Map<String, Report> registry = new HashMap<>();
static
{
// Violates OCP!
registerReport( GlobalReport.getInstance() );
registerReport( AvailablePackagesReport.getInstance() );
registerReport( BadgeReport.getInstance() );
registerReport( PlacementReport.getInstance() );
registerReport( TerminalReport.getInstance() );
registerReport( VerActReport.getInstance() );
}
private ReportRegistry() { }
static void registerReport(final Report report)
{
registry.put(report.getCode(), report);
}
public static Report lookup(final String reportCode)
{
return registry.get(reportCode);
}
}
However, ReportRegistry violates OCP, since we need to add an entry to its static block every time a new report is created.
My question is: how can I make any new subclass of Report to be registered automatically, without any explicit mentioning?
I would think OCP would be more applicable to Report itself, and that having ReportRegistry sitting outside of the class hierarchy would be a valid design.
That said, if you want to avoid modifying ReportRegistry each time you create a Report subclass, you could use some reflection tricks to seek out all such subclasses, or create an annotation that ReportRegistry could search for to register all classes with instances.
You should look at https://github.com/ronmamo/reflections. I have never tried this library but it looks like it does what you want (retrieving all subclasses of a known class).
You could then register them in your ReportRegistry static block.
I am using google-guice since a couple of days, and I am getting more and more impressed.
I created a MemberInjector to easily integrate the logging framework SLF4J, just with a additional annotation. That means instead of using always the long term:
private static final Logger LOG = LoggerFactory.getLogger(MyClass.class);
I am now just using:
#Log
Logger LOG;
This is really great, BUT:
I am also using a method-injection as a kind of starter function like this in the same class, AND if I access to the LOG instance there, it causes a NPE! Because it is not injected yet.
#Inject
public void start() {
//And here is the problem...
LOG.info("in start") //causes NPE, cause LOG is not injected yet
}
If I use the LOG instance in another (non-injected) method it works perfectly,.
Is there a way to change the injection order or is it possible to tell guice to inject the MemberInjector earlier? Cause I really would like to use the logging also in the method-injection part.
Thank for any hint.
One solution I found was to create just a additional listener that looks for a defined method like ("init" or "start") and just calls it after creation and injection of members.
See in module configuration:
#Override
protected void configure() {
bindListener(Matchers.any(), new InitMethodTypeListener());
//...
InitMethodTypeListener:
public class InitMethodTypeListener implements TypeListener {
private static final Logger log = LoggerFactory.getLogger(InitMethodTypeListener.class);
#SuppressWarnings("rawtypes")
static class InitInvoker implements InjectionListener {
#Override
public void afterInjection(final Object injectee) {
try {
log.info("Invoke init() from Class: {}", injectee.getClass().getName());
injectee.getClass().getMethod("init").invoke(injectee);
} catch (final Exception e) {
log.error(e.getMessage(), e);
}
}
public static final InitInvoker INSTANCE = new InitInvoker();
}
#SuppressWarnings("unchecked")
#Override
public <I> void hear(final TypeLiteral<I> type, final TypeEncounter<I> encounter) {
try {
if (type.getRawType().getMethod("init") != null) {
encounter.register(InitInvoker.INSTANCE);
}
} catch (final NoSuchMethodException | SecurityException e) {
// do nothing here, if not init-method found - no call
}
}
}
Maybe it not the straight forward way but it works. And so I am sure all members are injected well when the init-method is called.
With this implementation all objects that are under guice control their "init"-method will be called automatically after object creation and injection.
We are using Guice in our project for DI. Currently we have some configurations(properties) that we load a t server startup from a file. These are then bound to all the components & used for all the requests.
But now, we have multiple property files & load them at startup. These configurations can be different per REST(Jersey) request as they depend on the input.
So, we need to bind these configurations dynamically for each request. I looked into Guice API for #RequestScoped, but did not find anything specificallyu helpful.
There are few questions similar to this, but no luck yet. Can you please help me with this.
I'm providing 2 ways of doing this and both are request scoped.
Using HttpServletRequest, for classes where you can Inject request object.
Using ThreadLocal, Generic way. It can be used in any class.
(NOTE: This method wouldn't work if your creating new threads in your code and want to access the value. In which case you'll have to pass the values through Objects to those threads)
I meant something like this:
public class RequestFilter implements ContainerRequestFilter {
#Context
private HttpServletRequest request;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
List listOfConfig = //load Config;
request.setAttribute("LOADED_CONFIG",listOfConfig);
// If you want to access this value at some place where Request object cannot be injected (like in service layers, etc.) Then use below ThreadLocals.
ThreadLocalWrapper.getInstance().get().add("adbc"); // In general add your config here, instead of abdc.
}
}
My ThreadLocalWrapper looks like this:
public class ThreadLocalWrapper {
private static ThreadLocal<List<String>> listOfStringLocals; // You can modify this to a list of Object or an Object by itself.
public static synchronized ThreadLocal<List<String>> getInstance() {
if (listOfStringLocals == null) {
listOfStringLocals = new ThreadLocal<List<String>>() {
#Override
protected List<String> initialValue() {
return new ArrayList<String>();
}
};
}
return listOfStringLocals;
}
}
To Access the value:
In Controller - Inject HttpServletRequest Object and do getAttribute() to get the value. Since HttpServletRequest Object is requestScoped, you can set the loaded config. into this and access it in your controller's using request Object again.
In Any other part of the code - If HttpServletRequest is not available then you can always use the ThreadLocal example shown. To access this value.
public class GuiceTransactionImpl implements GuiceTransaction {
private String value = "";
public GuiceTransactionImpl(String text) {
value = text;
}
#Override
public String returnSuccess() {
return value + " Thread Local Value " + ThreadLocalWrapper.getInstance().get();
}
}
I have the following two classes and I am starting to see a pattern that even with my little Java background is screaming for a fix. Every new Object is going to require a set of Actions and the number of classes could grow out of hand. How do I refactor this into a generic DeleteAction class?
I know some of the answers will be use Hibernate, or JPA, or some Framework, but at the moment I can't utilize any of those tools. Oh, and our server only has jdk 1.4 (don't ask!). Thanks.
public class DeleteCommitmentAction implements ControllerAction {
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException {
CommitmentListDAO clDAO = new CommitmentListDAO();
CommitmentItemForm ciForm = new CommitmentItemForm(clDAO);
CommitmentItem commitmentItem = ciForm.deleteCommitmentItem(request);
RequestDispatcher view = request.getRequestDispatcher("views/commitmentView_v.jsp");
view.forward(request, response);
}
}
.
public class DeleteProgramAction implements ControllerAction {
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException {
ProgramDAO prgDAO = new ProgramDAO();
ProgramForm prgForm = new ProgramForm(prgDAO);
ProgramForm prg = prgForm.deleteProgram(request);
RequestDispatcher view = request.getRequestDispatcher("views/programView_v.jsp");
view.forward(request, response);
}
}
The approach that I think I need to take is to make interfaces. Starting with the DAO, I have created the following interface.
public interface GenericDao {
public void create(Object object, STKUser authenticatedUser) throws DAOException;
public void retreive(String id, STKUser authenticatedUser) throws DAOException;
public void update( final Object object, STKUser authenticatedUser) throws DAOException;
public void delete(String id, STKUser authenticatedUser) throws DAOException;
}
And then in my DeleteAction class I tried this
GenericDao gDAO = new GenericDao();
but Eclipse is stating "Cannot instantiate the type GenericDao" So now I am lost.
Update: Based on Péter Török's answer, here is what I have:
This is the servlet specific for handling operations on Commitment Items:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String schema = General_IO.getSchemaPath("TPQOT_463_COMMITMENT", request.getServerName());
CommitmentListDAO clDAO = new CommitmentListDAO();
CommitmentItemForm ciForm = new CommitmentItemForm(clDAO);
CommitmentItem commitmentItem = new CommitmentItem();
// I think this is the Application Controller Strategy
actionMap.put(null, new ListCommitmentsAction());
actionMap.put("list", new ListCommitmentsAction());
actionMap.put("view", new ViewCommitmentItemAction(schema));
//actionMap.put("delete", new DeleteCommitmentAction(schema));
// Change to the Generic DeleteAction and pass in the parameters
actionMap.put("delete", new DeleteAction(ciForm, commitmentItem, schema, "views/commitmentDeleteConfirm_v.jsp", "views/commitmentView_v.jsp" ));
// When happy with this approach, change other actions to the Generic Versions.
actionMap.put("sqlConfirmDelete", new DeleteCommitmentConfirmAction());
actionMap.put("edit", new EditCommitmentItemAction(schema));
actionMap.put("sqlUpdate", new UpdateCommitmentItemAction1(schema));
actionMap.put("new", new NewCommitmentFormAction(schema));
actionMap.put("sqlInsert", new InsertCommitmentItemAction1(schema));
String op = request.getParameter("method");
ControllerAction action = (ControllerAction) actionMap.get(op);
if (action != null) {
action.service(request, response);
} else {
String url = "views/errorMessage_v.jsp";
String errMessage = "Operation '" + op + "' not a valid for in '" + request.getServletPath() + "' !!";
request.setAttribute("message", errMessage);
request.getRequestDispatcher(url).forward(request, response);
}
}
And here is the Generic DeleteAction:
public class DeleteAction implements ControllerAction {
private Form form;
private Object obj;
private String schema = null;
private String xPage;
private String yPage;
public DeleteAction(Form form, Object item, String schema, String yPage, String xPage) {
this.form = form;
this.item = item; //passed in javabean??
this.schema = schema;
this.xPage = xPage;
this.yPage = yPage;
}
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
item = form.delete(request);
/* Database schema is described in xml files.
Hash maps of field names, sizes, and titles; foreign key names, titles,
lookup tables; and primary keys information are used to dynamically
build HTML forms in the views.
*/
HashMap test = ReadTableSchema.returnSchema(schema);
HashMap hshFields = (HashMap) test.get("hshFields");
HashMap hshForeignKeys = (HashMap) test.get("hshForeignKeys");
HashMap hshPrimaryKeys = (HashMap) test.get("hshPrimaryKeys");
request.setAttribute("hshFields", hshFields);
request.setAttribute("hshPrimaryKeys", hshPrimaryKeys);
request.setAttribute("hshForeignKeys", hshForeignKeys);
request.setAttribute("item", item);
request.setAttribute("form", form);
request.setAttribute("pageName", "Delete");
//Check for deletion authorization if successful forward to the confirmation page
if (form.isSucces()) {
request.setAttribute("message", "Please confirm permanent deletion of the data below.");
RequestDispatcher view = request.getRequestDispatcher(yPage);
view.forward(request, response);
} else {
// Not authorized to delete the data so just re-display
RequestDispatcher view = request.getRequestDispatcher(xPage);
view.forward(request, response);
}
}
}
then here is the interface (right now just for delete) that will be used by all forms.
public interface CRUD {
public Object delete(HttpServletRequest request);
}
You can't instantiate an interface, you need a concrete subclass for that. However, creating concrete subclasses just increases the number of classes, which you are trying to avoid. It is better to use composition instead of inheritance.
Namely, if you manage to make a common interface for the forms, and hide the actions deleteCommitmentItem, deleteProgram etc. behind one single method, you can parametrize your action instances with the required form (or a factory to provide this), e.g.:
public class GenericAction implements ControllerAction {
private Form form;
private String page;
GenericAction(Form form, String page) {
this.form = form;
this.page = page;
}
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException {
Item item = form.performDelete(request);
RequestDispatcher view = request.getRequestDispatcher(page);
view.forward(request, response);
}
}
...
CommitmentListDAO clDAO = new CommitmentListDAO();
CommitmentItemForm ciForm = new CommitmentItemForm(clDAO);
GenericAction deleteCommitmentAction = new GenericAction(ciForm, "views/commitmentView_v.jsp");
ProgramDAO prgDAO = new ProgramDAO();
ProgramForm prgForm = new ProgramForm(prgDAO);
GenericAction deleteProgramAction = new GenericAction(prgForm, "views/programView_v.jsp");
Thus you need no new classes for new kinds of actions, just instantiate GenericAction with different parameters.
It's clear by your naming that you already have implemented DAO objects (CommitmentListDAO, ProgramDAO). You should (probably) modify these classes to implement your new interface. Then your problem now becomes, how do you know which DAO to instantiate when you're in your generic delete action. Either that DAO should be passed into your action directly, or some other information on how to instantiate it (either a Class or factory) must be provided to your action.
GenericDAO is an interface, it cannot be instantiated directly. I don't know much Java, but every OOP language is pretty much the same. So what you need to do is create a concrete implementation of your interface (as a class) and then instantiate that instead. Something like this (sorry for the C# code but you get the idea):
public interface IGenericDAO {
void create(...);
}
and the implementation:
public class GenericDAO implements IGenericDAO {
public void create(...) {
/* implementation code */
}
}
Does that make sense?
One servlet per action is not unreasonable. Consider that if you have to do some action X, then you need to do X. Write a servlet to do X. It's that simple.
As you're noticing, this could lead to a lot of nearly identical servlets. That's ok because now you can use delegation (as Peter Torok recommends) or inheritance to move all the shared and abstracted code into one place. Which is better? Either is better than neither. You are 90% of the way to victory if you use one or both as appropriate.
I prefer a main servlet from which all others inherit. This allows me to wrap every service call in a consistent proper transaction in the base controller class. The subclasses never have to worry about it. This code shows the gist of it.
public class BaseControllerAction implements ControllerAction {
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException {
Connection conn = null;
try {
conn = getAConnection();
log.info("+++ top of "+getClass().getName());
conn.getTranaction().begin();
String dest = go(request, response, conn);
conn.getTransaction().commit();
RequestDispatcher view = request.getRequestDispatcher(dest);
view.forward(request, response);
} catch (Exception e) {
conn.getTransaction().rollback();
} finally {
conn.close();
log.info("--- Bottom of "+getClass().getName());
}
protected abstract String go(HttpServletRequest request, HttpServletResponse response, Transaction transaction) throws ServletException;
}
and now you can implement your servlet:
public class DeleteCommitmentAction extends BaseControllerAction {
protected String go(HttpServletRequest request, HttpServletResponse response, Connection conn) throws ServletException {
// Given what this method is supposed to do, it's very reasonable
// to refer to models and DAOs related to deleting commitments.
Long id = new Long(request.getParameter("id"));
CommitmentDAO.delete(conn, id);
return "views/commitmentView_v.jsp";
}
}
So now none of your servlets have to worry about transactions or opening and closing connections. They only have to worry about the details of their specific task. Obviously I don't know your system so I can't give detailed suggestions but this is how I did two decent-sized apps recently. They have about 30 servlets each. But the servlets are generally about 15 lines long. I ended up with a utility class that implemented the sorts of tasks needed by all the servlets. Poor man's delegation, perhaps.
Interface can't be instantiated. Instead, you should create a concrete class implementing the interface and instantiate this class.
I have a large library of wicket components that are annotated with a custom annotation #ReferencedResource or another annotation #ReferencedResources, that has a ReferencedResouce[] value() parameter to allow multiple annotations.
Here is a sample code snippet:
#ReferencedResources({
#ReferencedResource(value = Libraries.MOO_TOOLS, type = ResourceType.JAVASCRIPT),
#ReferencedResource(value = "behaviors/promoteSelectOptions", type = ResourceType.JAVASCRIPT) })
public class PromoteSelectOptionsBehavior extends AbstractBehavior{
...
}
So far, I use apt to check that the referenced resources actually exist. E.g.
#ReferencedResource(value = "behaviors/promoteSelectOptions",
type = ResourceType.JAVASCRIPT)
will cause a compilation failure unless the file js/behaviors/promoteSelectOptions.js can be found on the class path. This part works nicely.
Now I am also a fan of DRY and I would like to use the same annotation to actually inject the resources into the Objects when they are created. Using AspectJ, I have implemented a part of this.
The annotated Objects are always either instances of Component or AbstractBehavior.
For components, things are easy, just match after the constructor. Here's an advice that does this:
pointcut singleAnnotation() : #within(ReferencedResource);
pointcut multiAnnotation() : #within(ReferencedResources);
after() : execution(Component+.new(..)) && (singleAnnotation() || multiAnnotation()){
final Component component = (Component) thisJoinPoint.getTarget();
final Collection<ReferencedResource> resourceAnnotations =
// gather annotations from cache
this.getResourceAnnotations(component.getClass());
for(final ReferencedResource annotation : resourceAnnotations){
// helper utility that handles the creation of statements like
// component.add(JavascriptPackageResource.getHeaderContribution(path))
this.resourceInjector.inject(component, annotation);
}
}
For behaviors however, I need to attach the resources to a response, not to the behavior itself. Here are the pointcuts I use:
pointcut renderHead(IHeaderResponse response) :
execution(* org.apache.wicket.behavior.AbstractBehavior+.renderHead(*))
&& args(response);
And here is the advice:
before(final IHeaderResponse response) :
renderHead(response) && (multiAnnotation() || singleAnnotation()) {
final Collection<ReferencedResource> resourceAnnotations =
this.getResourceAnnotations(thisJoinPoint.getTarget().getClass());
for(final ReferencedResource resource : resourceAnnotations){
this.resourceInjector.inject(response, resource);
}
}
This also works nicely if the class overrides the renderHead(response) method, but in many cases that's just not necessary because a super class already implements the base functionality while the child class only adds some configuration. So one solution would be to let these classes define a method like this:
#Override
public void renderHead(IHeaderResponse response){
super.renderHead(response);
}
I would hate this, because this is dead code, but currently this is the only working option I see, so I am looking for other solutions.
EDIT:
I have created a working solution using APT and sun javac calls. However, this leads to the next problem: Running APT and AspectJ in the same project using maven.
Anyway, as soon as I have some free time, I'll post the answer to this question (or parts of it).
Answering my own question:
Here is the relevant bit of code to insert the super call:
these fields are all initialized in init(env) or process(annotations, roundEnv):
private static Filer filer;
private static JavacProcessingEnvironment environment;
private static Messager messager;
private static Types types;
private static JavacElements elementUtils;
private Trees trees;
private TreeMaker treeMaker;
private IdentityHashMap<JCCompilationUnit, Void> compilationUnits;
private Map<String, JCCompilationUnit> typeMap;
And here is the logic that is called if a subtype of AbstractBehavior that has the annotation does not override the renderHead(response) method:
private void addMissingSuperCall(final TypeElement element){
final String className = element.getQualifiedName().toString();
final JCClassDecl classDeclaration =
// look up class declaration from a local map
this.findClassDeclarationForName(className);
if(classDeclaration == null){
this.error(element, "Can't find class declaration for " + className);
} else{
this.info(element, "Creating renderHead(response) method");
final JCTree extending = classDeclaration.extending;
if(extending != null){
final String p = extending.toString();
if(p.startsWith("com.myclient")){
// leave it alone, we'll edit the super class instead, if
// necessary
return;
} else{
// #formatter:off (turns off eclipse formatter if configured)
// define method parameter name
final com.sun.tools.javac.util.Name paramName =
elementUtils.getName("response");
// Create #Override annotation
final JCAnnotation overrideAnnotation =
this.treeMaker.Annotation(
Processor.buildTypeExpressionForClass(
this.treeMaker,
elementUtils,
Override.class
),
// with no annotation parameters
List.<JCExpression> nil()
);
// public
final JCModifiers mods =
this.treeMaker.Modifiers(Flags.PUBLIC,
List.of(overrideAnnotation));
// parameters:(final IHeaderResponse response)
final List<JCVariableDecl> params =
List.of(this.treeMaker.VarDef(this.treeMaker.Modifiers(Flags.FINAL),
paramName,
Processor.buildTypeExpressionForClass(this.treeMaker,
elementUtils,
IHeaderResponse.class),
null));
//method return type: void
final JCExpression returnType =
this.treeMaker.TypeIdent(TypeTags.VOID);
// super.renderHead(response);
final List<JCStatement> statements =
List.<JCStatement> of(
// Execute this:
this.treeMaker.Exec(
// Create a Method call:
this.treeMaker.Apply(
// (no generic type arguments)
List.<JCExpression> nil(),
// super.renderHead
this.treeMaker.Select(
this.treeMaker.Ident(
elementUtils.getName("super")
),
elementUtils.getName("renderHead")
),
// (response)
List.<JCExpression> of(this.treeMaker.Ident(paramName)))
)
);
// build code block from statements
final JCBlock body = this.treeMaker.Block(0, statements);
// build method
final JCMethodDecl methodDef =
this.treeMaker.MethodDef(
// public
mods,
// renderHead
elementUtils.getName("renderHead"),
// void
returnType,
// <no generic parameters>
List.<JCTypeParameter> nil(),
// (final IHeaderResponse response)
params,
// <no declared exceptions>
List.<JCExpression> nil(),
// super.renderHead(response);
body,
// <no default value>
null);
// add this method to the class tree
classDeclaration.defs =
classDeclaration.defs.append(methodDef);
// #formatter:on turn eclipse formatter on again
this.info(element,
"Created renderHead(response) method successfully");
}
}
}
}