Dynamic Google Juice injection depending on value of an annotation [duplicate] - java

Is there any way to bind with provider which interprets target's annotation value in Google Guice?
Example:
bind(Resource.class)
.annotatedWith(MyAnnotation.class)
.toProvider(new MyProvider<MyAnnotation, Resource>{
public Resource get(MyAnnotation anno){
return resolveResourceByAnnoValue(anno.value());
}
});
I want to initialize field of an Android Activity class by annotated binding.
It should have to take multiple resources by it's unique Id.
Original Way:
public class TestActivity extends Activity{
private TextView textView;
private Button testButton;
public void onAfterCreate(...){
// set UI declaration resource.
setContentView(R.layout.activity_test);
// initialize fields, it must be done after setting ui definition.
textView = (TextView) findViewById(R.id.textView);
.... initialize other fields, hook them...
...
}
I want to bind UI and it's field in declarative way, not pragmatically likes above:
#ResourceID(R.layout.activity_test)
public class TestActivity extends InjectiveActivity{
#ResourceID(R.id.textView) // Auto generated static resource id constant
private TextView textView;
#ResourceID(R.id.testButton)
private Button testButton;
...
}

This isn't possible as such.
If #MyAnnotation is a binding annotation, it will be compared using its equals method. #MyAnnotation(5) Resource will be bound to #MyAnnotation(5) Resource, and that will not match at all compared to #MyAnnotation(6) Resource. Check out this SO answer for more. As in that answer, you could loop through your possible annotation values and bind each one individually, if you feel like it.
If #MyAnnotation isn't a binding annotation, you won't be able to access it at all from your provider. As mentioned in this SO answer, it is a rejected feature to add injection-site information to the provider or dependency itself.
Your best bet is to create an #Assisted injection (or manual factory) to accept the parameter:
class MyConsumer {
final Resource resource;
#Inject MyConsumer(Resource.Factory resourceFactory) {
int previouslyAnnotatedValue = 5;
this.resource = resourceFactory.createWithValue(previouslyAnnotatedValue);
}
}
You may also consider using Custom Injections, which will let you use an arbitrary annotation other than #Inject, which may use runtime annotation values however you'd like.

Here is an example in Scala (I like using Scala for prototyping, it's Java in a different dress after all) which I came up with after wondering about it myself in Dynamic Google Juice injection depending on value of an annotation
import java.lang.reflect.{Constructor, Parameter}
import java.util.concurrent.atomic.AtomicReference
import javax.inject.{Inject, Named, Provider}
import com.google.inject.matcher.Matchers
import com.google.inject.spi.ProvisionListener.ProvisionInvocation
import com.google.inject.{AbstractModule, Binder, Guice}
import com.google.inject.spi.{DependencyAndSource, ProviderInstanceBinding, ProvisionListener}
import com.typesafe.config.ConfigFactory
import net.codingwell.scalaguice.InjectorExtensions._
import net.codingwell.scalaguice.ScalaModule
import scala.collection.JavaConverters._
object GuiceExperiments extends App {
val injector = Guice.createInjector(new MyModule())
val some = injector.instance[Some]
println(some)
some.go()
}
trait Some {
def go(): Unit
}
class Impl #Inject()(
#Named("a.a.a") hello: String,
#Named("a.a.b") bello: String,
#Named("a.b.a") kello: String
) extends Some {
override def go() = {
println(hello)
println(bello)
println(kello)
}
}
abstract class DynamicProvider[T >: Null](binder: Binder) extends Provider[T] {
private[this] val nextValue = new AtomicReference[T]
binder.bindListener(Matchers.any(), new ProvisionListener {
private[this] def tryProvide(target: DependencyAndSource): Unit = {
val dependency = target.getDependency
val injectionPoint = dependency.getInjectionPoint
val parameterIndex = dependency.getParameterIndex
injectionPoint.getMember match {
case constructor: Constructor[_] =>
val parameter = constructor.getParameters()(parameterIndex)
nextValue.set(getFor(parameter))
}
}
override def onProvision[V](provision: ProvisionInvocation[V]): Unit = {
provision.getBinding match {
case binding: ProviderInstanceBinding[_] if binding.getUserSuppliedProvider eq DynamicProvider.this =>
provision.getDependencyChain.asScala.lastOption.foreach(tryProvide)
case _ => ()
}
}
})
final override def get(): T = nextValue.getAndSet(null)
def getFor(parameter: Parameter): T
}
class MyModule extends AbstractModule with ScalaModule {
override def configure(): Unit = {
bind[Some].to[Impl]
bind[String].annotatedWith[Named].toProvider(new DynamicProvider[String](binder) {
override def getFor(parameter: Parameter): String = {
if (parameter.isAnnotationPresent(classOf[Named])) {
parameter.getAnnotation(classOf[Named]).value()
} else {
null
}
}
})
}
}
this only inserts the value of the #Named, but looks like it pretty damn works. so much for not possible.

Related

Unit testing extended AEM core component - delegate pattern null reference exception

I am trying to write a unit test for an extended AEM core component - a 'button' with an extra field. I use the delegation pattern, and Lombok to reduce implementation code.
My unit test is failing when attempting to get the button ID (inherited from the button super-type) - with a null reference exception - because 'button' is null.
Why would that be? Have I set up my unit test incorrectly? Or could it be that I have used the delegation pattern for the core component incorrectly?
It is driving me crazy!
INTERFACE:
#ProviderType
public interface ExtendedButton extends Button {
String RESOURCE_TYPE = "myproject/components/extendedbutton";
String getVariant();
}
IMPL:
#Model(
adaptables = { Resource.class, SlingHttpServletRequest.class },
adapters = { ExtendedButton.class, Button.class, ComponentExporter.class },
resourceType = ExtendedButton.RESOURCE_TYPE,
defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL
)
#Exporter(name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, extensions = ExporterConstants.SLING_MODEL_EXTENSION)
public class ExtendedButtonImpl implements ExtendedButton {
#Delegate
#Self
#Via(type = ResourceSuperType.class)
private Button button;
#ValueMapValue
#Getter
private String variant;
// EXAMPLE
// without lombok, the getter for button ID would be;
public String getId() {
return (null != button) ? button.getId() : null;
}
}
UNIT TEST CODE:
#ExtendWith(AemContextExtension.class)
class ExtendedButtonModelTest {
private final AemContext context = new AemContextBuilder()
.plugin(CORE_COMPONENTS)
.build();
private ExtendedButton model;
#BeforeEach
public void setup() {
context.create().resource("/apps/myproject/components/extendedbutton",
PROPERTY_RESOURCE_SUPER_TYPE, "core/wcm/components/button/v2/button");
Page page = context.create().page("/content/test-page");
context.currentResource(context.create().resource(page, "extendedbutton",
PROPERTY_RESOURCE_TYPE, ExtendedButton.RESOURCE_TYPE,
JCR_TITLE, "button text",
"variant", "light",
"id", "button id",
"linkURL", "https://google.com",
"linkTarget", "_blank",
"accessibilityLabel", "button label"
));
model = context.request().adaptTo(ExtendedButton.class);
}
// UNIT TEST SUCCEEDS
#Test
void testGetVariant() {
String val = model.getVariant();
assertNotNull(val);
assertEquals("light", val);
}
// UNIT TEST THROWS NULL POINTER EXCEPTION ON MODEL
#Test
void testGetButtonId() {
String val = model.getId();
assertNotNull(val);
assertEquals("button-id", val);
}
}
Oh my! This turned out to be a very, very simple issue. In the above unit test code, I used two constants;
PROPERTY_RESOURCE_SUPER_TYPE
PROPERTY_RESOURCE_TYPE
These were incorrect - and from the wrong import library, since they were "resourceSuperType" and "resourceType" respectively - missing the "sling:" prefix!!!!!!
The correct constants, are;
import static org.apache.sling.jcr.resource.api.JcrResourceConstants.SLING_RESOURCE_SUPER_TYPE_PROPERTY;
import static org.apache.sling.jcr.resource.api.JcrResourceConstants.SLING_RESOURCE_TYPE_PROPERTY;
The fundamental line to the unit test, being;
context.create().resource("/apps/myproject/components/extendedbutton",
SLING_RESOURCE_SUPER_TYPE_PROPERTY, "core/wcm/components/button/v2/button");
which instructs the unit test which core component to extend from.

Chained creational OOP design pattern problem

I am creating a class that is responsible for validating a configuration. This class calls other classes that validate said config by creating new instances in the form of a chain. At first glance, the code structure looks horrible, but It works. Anyway, I think it's not the best way to handle this logic.
I leave here a simplified version of the code in TypeScript, but I also leave it in Python and Java for reference only:
class Validator {
private _notValidatedConfig: NotValidatedConfig
constructor(notValidatedConfig: NotValidatedConfig) {
this._notValidatedConfig = notValidatedConfig
}
validateConfig(): ValidatedConfig {
return (
new Phase4Validation(
new Phase3Validation(
new Phase2Validation(
new Phase1Validation(
this._notValidatedConfig
).validate()
).validate()
).validate()
).validate()
)
}
// Alternative
validateConfig2(): ValidatedConfig {
const validatedPhase1Config: ValidatedPhase1Config = new Phase1Validation(this._notValidatedConfig).validate()
const validatedPhase2Config: ValidatedPhase2Config = new Phase2Validation(validatedPhase1Config).validate()
const validatedPhase3Config: ValidatedPhase3Config = new Phase3Validation(validatedPhase2Config).validate()
const validatedPhase4Config: ValidatedPhase4Config = new Phase4Validation(validatedPhase3Config).validate()
return validatedPhase4Config;
}
}
Python
Java Disclaimer: I don't have any experience with Java, so maybe there are some syntax errors.
The "alternative" is the same code, but not directly chained, instead, for every validation, it's creating a new variable.
I think the "alternative" is more readable but performs worse.
What do you think about this code? what did you change? How would you face this problem or with what design pattern or framework? (programming language doesn't matter for these question)
I would create a base class Validation and just create derived classes from it if it is necessary to add new validation:
public abstract class Validation
{
public Validation(string config)
{
}
public abstract string Validate();
}
and its concrete implementations:
public class Phase1Validation : Validation
{
public Phase1Validation(string config) : base(config)
{}
public override string Validate()
{
if (true)
return null;
return "There are some errors Phase1Validation";
}
}
public class Phase2Validation : Validation
{
public Phase2Validation(string config) : base(config)
{
}
public override string Validate()
{
if (true)
return null;
return "There are some errors in Phase2Validation";
}
}
and then just create a list of validators and iterate through them to find errors:
public string Validate()
{
List<Validation> validations = new List<Validation>()
{
new Phase1Validation("config 1"),
new Phase2Validation("config 2")
};
foreach (Validation validation in validations)
{
string error = validation.Validate();
if (!string.IsNullOrEmpty(error))
return error;
}
return null; // it means that there are no errors
}
UPDATE:
I've little bit edited my classes to fit your new question requirements:
validations should be ordered. Added Order property
get config from previous validation and send it to the next validation
It can be seen that this approach allows to avoid to write nested classes like this:
new Phase4Validation(
new Phase3Validation(
new Phase2Validation(...).validate()
).validate()
).validate()
So you can add new classes without editing validation classes and it helps to keep Open CLosed Principle of SOLID principles.
So the code looks like this:
Abstractions:
public abstract class Validation
{
// Order to handle your validations
public int Order { get; set; }
// Your config file
public string Config { get; set; }
public Validation(int order)
{
Order = order;
}
// "virtual" means that method can be overriden
public virtual string Validate(string config)
{
Config = config;
if (true)
return null;
return "There are some errors Phase1Validation";
}
}
And its concrete implementations:
public class Phase1Validation : Validation
{
public Phase1Validation(int order) : base(order)
{
}
}
public class Phase2Validation : Validation
{
public Phase2Validation(int order) : base(order)
{
}
}
And method to validate:
string Validate()
{
List<Validation> validations = new List<Validation>()
{
new Phase1Validation(1),
new Phase2Validation(2)
};
validations = validations.OrderBy(v => v.Order).ToList();
string config = "";
foreach (Validation validation in validations)
{
string error = validation.Validate(config);
config = validation.Config;
if (!string.IsNullOrEmpty(error))
return error;
}
return null; // it means that there are no errors
}
I leave here my own answer, but I'm not going to select it as correct because I think there exist better answers (besides the fact that I am not very convinced of this implementation).
A kind of Decorator design pattern allowed me to do chain validation with greater use of the dependency injection approach.
I leave here the code but only for Python (I have reduced the number of phases from 4 to 2 to simplify the example).
from __future__ import annotations
import abc
from typing import cast
from typing import Any
from typing import TypedDict
NotValidatedConfig = dict
ValidatedConfig = TypedDict("ValidatedConfig", {"foo": Any, "bar": Any})
class InvalidConfig(Exception):
...
# This class is abstract.
class ValidationHandler(abc.ABC):
_handler: ValidationHandler | None
def __init__(self, handler: ValidationHandler = None):
self._handler = handler
# This method is abstract.
#abc.abstractmethod
def _validate(self, not_validated_config: NotValidatedConfig):
...
def _chain_validation(self, not_validated_config: NotValidatedConfig):
if self._handler:
self._handler._chain_validation(not_validated_config)
self._validate(not_validated_config)
def get_validated_config(self, not_validated_config: NotValidatedConfig) -> ValidatedConfig:
self._chain_validation(not_validated_config)
# Here we convert (in a forced way) the type `NotValidatedConfig` to
# `ValidatedConfig`.
# We do this because we already run all the validations chain.
# Force a type is not a good way to deal with a problem, and this is
# the main downside of this implementation (but it works anyway).
return cast(ValidatedConfig, not_validated_config)
class Phase1Validation(ValidationHandler):
def _validate(self, not_validated_config: NotValidatedConfig):
if "foo" not in not_validated_config:
raise InvalidConfig('Config miss "foo" attr')
class Phase2Validation(ValidationHandler):
def _validate(self, not_validated_config: NotValidatedConfig):
if not isinstance(not_validated_config["foo"], str):
raise InvalidConfig('"foo" must be an string')
class Validator:
_validation_handler: ValidationHandler
def __init__(self, validation_handler: ValidationHandler):
self._validation_handler = validation_handler
def validate_config(self, not_validated_config: NotValidatedConfig) -> ValidatedConfig:
return self._validation_handler.get_validated_config(not_validated_config)
if __name__ == "__main__":
# "Pure Dependency Injection"
validator = Validator((Phase2Validation(Phase1Validation())))
validator.validate_config({"foo": 1, "bar": 1})
What is the problem with this approach?: the lightweight way in which the types are concatenated. In the original example, the Phase1Validation generates a ValidatedPhase1Config, which is safely used by the Phase2Validation. With this implementation, each decorator receives the same data type to validate, and this creates safety issues (in terms of typing). The Phase1Validation gets NotValidatedConfig, but the Phase2Validation can't use that type to do the validation, they need the Phase1Validation.

UnitTesting: how to pass my mock class in the read code

I am using hazelcast in my project and I want to unit test some function but i do not want it to connect to real hazelcast and perform test on it for that i created a custom mock class which simply uses scala map because in hazelcast maps also there
here is my code
trait UserRepository {
def getUserObj(id: String):Option[User]
def addToUserRepo(user: User)
}
class UserRepo extends UserRepository{
def getUserObj(id: String):Option[User] = {
val userMap = hcastClient.getMap[String, User]("UserMap")
val userObj = userMap.get(id)
Option(userObj)
}
def addToUserRepo(user: User) = {
val directUserMap: IMap[String, User] = hcastClient.getMap[String,User]("UserMap")
directUserMap.set(user.uuid, user)
}
and here i created a simple customized mocked version class where the functionality is same just; replaced it with scala map:
class UserRepoMock extends UserRepository {
val map:Map[String,User]=Map[String,User]()
def getUserMap:Map[String,User] = {
map
}
def getUserObj(id: String):User = {
val userMap = getUserMap
val userObj = userMap.get(id)
userObj
}
def addToUserRepo(user: User) = {
val userMap = getUserMap
userMap.put(user.uuid, user)
}
class UserUtil(userRepo:UserRepo) {
def addUser(user:User):Boolean={
try{
userRepo.addToUserRepo(user)
true
}
catch {
case e:Exception=>false
}
def getUser(id:String):User={
val user=userRepo.getUserObj(id)
user
}
Mow i want to unit test methods addUser and getUserof UserUtil class
by doing like this:
class UserUtilTest extends funSpec {
val userUtil=new UserUtil(new UserRepoMock)
userUtil.addUser //perform unit test on it
userUtil.getUser //perform unit test on it
// instead of doing this val userUtil=new UserUtil(new UserRepo)
}
but the compiler not allowing me to do that,there is something which i am missing, Please help me how can i achieve the desired functionality
This is the compiler error:
type mismatch; found : testhcastrepo.UserRepoMock required: com.repositories.UserRepo
Well: your utils class says:
class UserUtil(userRepo:UserRepo)
So it needs an instance of UserRepo.
But then your are passing an instance of UserRepoMock. A UserRepoMock is a UserRepository, as UserRepo is; but a UserRepoMock is not a UserRepo!
Probably it is as simple as changing the utils to
class UserUtil(userRepo:UserRepository)
to indicate that you don't want to specify a specific class. Instead you simply say: anything that has the trait will do!
Beyond that: the real answer might be: have a look at your naming habits. You see, those two names UserRepositor and UserRepo; they are pretty "close" to each other; and it is not at all clear, what the difference between the two is. If the names would be more distinct, like UserRepositoryTrait and HCastUserRepository you probably would not have made this mistake in the first place (not sure my suggestions are "good" names according to scala conventions; but they are just meant to give you an idea).

Guice: How to change injection on runtime based on a (dynamic web property)

The following is an approximation of the problem I'm facing.
Think we have a password validator with some rules.
public interface RuleChecker{
//Checks for a password strenght, returns 10
//for strong or 0 for soft password.
int check(String pass);
}
And then we have several implementations, our service will only accept the password if it is over 8 score.
public class NoCheck implements RuleChecker {
public int check(String pass){return 10;}
}
public class LengthCheck implements RuleChecker{
...
}
public class AlphanumericCheck implements RuleChecker{
...
}
public class AlphaAndLenghtCheckAdapter implements RuleChecker{
...
}
But for testing purposes, we want to implement a webservice within the application where we can "admin" those rules, and select which ones to have.
public class PasswordCheckService{
private RuleChecker checker;
#Inject
public PasswordCheckService(final RuleChecker checker){
this.checker = checker;
}
public boolean checkPassword(String password){
return checker.check(password) > 8;
}
}
So, is there any way in Guice, to change at runtime, the injection a service has?
Example:
We started the application and by default LengthCheck is selected and injected on the application, at the website we select the NoCheck checkbox and save options, which is stored into the database, can I configure Guice to automatically change the bean the service had injected before? so from now and on there will be no checks on new passwords?
--
As for now, I have found those topics
Google Guice and varying injections at runtime
But i dont know if that kind of providers fits my problem.
Guice runtime dependency parameters reinjection
That nice question is talking something similar, but not what I'm looking form.
guice: runtime injection/binding at command line
This is the closest to my problem but he only does on starting "runtime" and does not change it over the time.
Any helps?
Thank you!
Using the tip of the first comment I implemented this POC but still does not works, if you change select another button the service bean is not updated.
https://bitbucket.org/ramonboza/guicedynamicconfig
Create a provider for each field type (login, password, birth date...), with a parameter to change the implementation to return.
public class MyModule extends AbstractModule {
public void configure() {
bind(RuleChecker.class).annotatedWith(named("password")).toProvider(PasswordRuleCheckerProvider.class);
bind(RuleChecker.class).annotatedWith(named("login")).toProvider(LoginRuleCheckerProvider.class);
}
}
public static class PasswordRuleCheckerProvider implements Provider<RuleChecker> {
private static CheckType type = CheckType.ALPHANUMERIC;
// static type setter.
public RuleChecker get() {
// it would even be better if you could use singletons here.
switch(type) {
case LENGTH:
return new LengthCheck();
case ALPHANUMERIC:
return new AlphanumericCheck();
case ALPHALENGTH:
return new AlphaAndLenghtCheckAdapter();
case NONE:
default:
return NoCheck();
}
}
}
// Almost same provider for your LoginRuleCheckerProvider. You could do something generic.
In your admin section you change "type" value, so your rules will change. It can affect a limited set of fields, thanks to the annotations. For instance : PasswordRuleCheckerProvider.setType(CheckType.LENGTH);. Will only affect fields with #Named('password').
You have to declare your fields and services like this :
public abstract class DynamicService {
protected void updateService() {
// Reinject with the new implementations the members.
App.getInjector().injectMembers(this);
}
}
public class PasswordCheckService extends DynamicService {
#Inject
#Named("password")
private RuleChecker passwordChecker;
public void changePasswordCheckType(CheckType type) {
PasswordRuleCheckerProvider.setType(type);
// Reinject, so you have your new implementation.
updateService();
}
// [...]
}

AOP or APT for overriding methods from super classes

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");
}
}
}
}

Categories