Trying to clean up some nasty code, for which we dont have the source code. Imagine something like this:
public class Driver{
private String paramA;
private String paramB;
new Driver(HugeAndOverbloatedObject object)
{
paramA = object.getSubObject4711().getParamX();
paramB = object.getSubObject4712().getParamY();
}
}
This third library has this all over the place: tight coupling via constructors, eventhough the classes are hardly related. The rude combination of private members and forced constructor inheritance make the extension of the code virtually impossible without creating "sloppy" constructor parameter objects.
So I am trying to manipulate the classes via AspectJ and compile time weaving, so I can slim down on the constructors, to something like this:
Driver driver = new Driver("paramA", "paramB");
I think this should be possible, and I have made some progress. If I have something like this:
public aspect NewConstructor {
Driver.new(String parameterA, String parameterB){
//New Constructor Code
}
}
and run this through the weaver I actually find a new constructor in the driver, but not quite as I expected.
Issue: Unexpected third Parameter in the woven class
I was hoping I can invoke it with two parameters:
new Driver("paramA", "paramB")
Instead I need to invoke it with three parameters:
new Driver("paramA", "paramB", new NewConstructor())
Why do I need to instantiate a new instance of the aspect and pass it as an argument? Can this be prevented?
Something odd is going on here. You should not need to add the aspect as a third argument to the constructor. In fact, when I try this myself using the following class and aspect, I do not get any compile errors:
Java class:
package pack;
public class Driver {
public static void main(String[] args) {
new Driver("paramA", "paramB");
}
}
Aspect:
package pack;
public aspect NewConstructor {
public pack.Driver.new(String parameterA, String parameterB){
}
}
Are your Java class and aspect in different projects? Are you using an aspect path and/or in path? Are you using load time weaving?
If after doing a full build of your project you still see the probem, it's worth raising a bug for AspectJ.
Related
I have many classes (45 at least). Each one has its own method to validate something that is repeated in all the classes, so I have the code repeated in all those classes. I'd like to have one method and call it from all the classes.
If have the following code to know if a mobile device is connecting to the server
private boolean isMobileDevice(HttpServletRequest request) {
String userAgent = request.getHeader("user-agent");
return userAgent.indexOf("Windows CE") != -1;
}
As said before, This method is repeated in many classes
Is it possible in Intellij Idea and/or Eclipse to do that refactor? and How can I perform that refactor?
private boolean isMobileDevice(HttpServletRequest request) {
String userAgent = request.getHeader("user-agent");
return userAgent.indexOf("Windows CE") != -1;
}
I bet that my Eclipse will warn me that this method can be declared as static, because it does not use any fields of enclosing class - such method should be declared as static to let you know that it is not essentially needed in enclosing class, and if there will be a reason (having 45 methods in place of one is THE REASON) you can move it to some other class, and just call it as public or package method.
EDIT: It did: The method isMobileDevice(HttpServletRequest) from the type Test can be declared as static:
So:
Copy it to some other class, make it public static boolean isMobileDevice(HttpServletRequest request) and use in every classes where it was private boolean.
That's all, but I don't see and way to make it with automatic refactor.
With Intellij you could try "Refactor" > "Find and Replace Code Duplicates...".
It will replace the duplicate code by a static function.
I've try to expose to the client(gwt) an aspectJ method through gwt-rpc, but the gwt client can't find the method defined in an aspect. The class that i expose implements IsSerializable and only it's method are visible to the client interface...the method added by their aspect contrariwise no. How i can fix this? thanks in advice.
p.s. i post a little example for more clarity:
this is the class...
public class Example implements IsSerializable{
private String name;
public setName(String name){
this.name=name
}
}
and this is the aspect...
privileged aspect Example_x{
public int Example.getVersion() {
return this.version;
}
}
The Example.getVersion() method is unavailable on the client side.
TNX
This won't work, as GWT needs access to the source of any Java class that is exposed to the client side. This is necessary to compile them from Java to Javascript. If you modify your classes using AspectJ, the added methods will not be visible to the GWT compiler and therefore not to the client.
I'd say AspectJ is simply the wrong tool for this task. If you want to add some methods to existing classes you could write a (possibly generic) container class that contains an instance of Example as well as the version information from Example_x.
This is pretty basic, but sort of a generic issue so I want to hear what people's thoughts are. I have a situation where I need to take an existing MSI file and update it with a few standard modifications and spit out a new MSI file (duplication of old file with changes).
I started writing this with a few public methods and a basic input path for the original MSI. The thing is, for this to work properly, a strict path of calls has to be followed from the caller:
var custom = CustomPackage(sourcemsipath);
custom.Duplicate(targetmsipath);
custom.Upgrade();
custom.Save();
custom.WriteSmsXmlFile(targetxmlpath);
Would it be better to put all the conversion logic as part of the constructor instead of making them available as public methods? (in order to avoid having the caller have to know what the "proper order" is):
var custom = CustomPackage(sourcemsipath, targetmsipath); // saves converted msi
custom.WriteSmsXmlFile(targetxmlpath); // saves optional xml for sms
The constructor would then directly duplicate the MSI file, upgrade it and save it to the target location. The "WriteSmsXmlFile is still a public method since it is not always required.
Personally I don't like to have the constructor actually "do stuff" - I prefer to be able to call public methods, but it seems wrong to assume that the caller should know the proper order of calls?
An alternative would be to duplicate the file first, and then pass the duplicated file to the constructor - but it seems better to have the class do this on its own.
Maybe I got it all backwards and need two classes instead: SourcePackage, TargetPackage and pass the SourcePackage into the constructor of the TargetPackage?
I'd go with your first thought: put all of the conversion logic into one place. No reason to expose that sequence to users.
Incidentally, I agree with you about not putting actions into a constructor. I'd probably not do this in the constructor, and instead do it in a separate converter method, but that's personal taste.
It may be just me, but the thought of a constructor doing all these things makes me shiver. But why not provide a static method, which does all this:
public class CustomPackage
{
private CustomPackage(String sourcePath)
{
...
}
public static CustomPackage Create(String sourcePath, String targetPath)
{
var custom = CustomPackage(sourcePath);
custom.Duplicate(targetPath);
custom.Upgrade();
custom.Save();
return custom;
}
}
The actual advantage of this method is, that you won't have to give out an instance of CustomPackage unless the conversion process actually succeeded (safe of the optional parts).
Edit In C#, this factory method can even be used (by using delegates) as a "true" factory according to the Factory Pattern:
public interface ICustomizedPackage
{
...
}
public class CustomPackage: ICustomizedPackage
{
...
}
public class Consumer
{
public delegate ICustomizedPackage Factory(String,String);
private Factory factory;
public Consumer(Factory factory)
{
this.factory = factory;
}
private ICustomizedPackage CreatePackage()
{
return factory.Invoke(..., ...);
}
...
}
and later:
new Consumer(CustomPackage.Create);
You're right to think that the constructor shouldn't do any more work than to simply initialize the object.
Sounds to me like what you need is a Convert(targetmsipath) function that wraps the calls to Duplicate, Upgrade and Save, thereby removing the need for the caller to know the correct order of operations, while at the same time keeping the logic out of the constructor.
You can also overload it to include a targetxmlpath parameter that, when supplied, also calls the WriteSmsXmlFile function. That way all the related operations are called from the same function on the caller's side and the order of operations is always correct.
In such situations I typicaly use the following design:
var task = new Task(src, dst); // required params goes to constructor
task.Progress = ProgressHandler; // optional params setup
task.Run();
I think there are service-oriented ways and object-oritented ways.
The service-oriented way would be to create series of filters that passes along an immutable data transfer object (entity).
var service1 = new Msi1Service();
var msi1 = service1.ReadFromFile(sourceMsiPath);
var service2 = new MsiCustomService();
var msi2 = service2.Convert(msi1);
service2.WriteToFile(msi2, targetMsiPath);
service2.WriteSmsXmlFile(msi2, targetXmlPath);
The object-oriented ways can use decorator pattern.
var decoratedMsi = new CustomMsiDecorator(new MsiFile(sourceMsiPath));
decoratedMsi.WriteToFile(targetMsiPath);
decoratedMsi.WriteSmsXmlFile(targetXmlPath);
GWT.create() is the reflection equivalent in GWT,
But it take only class literals, not fully qualified String for the Class name.
How do i dynamically create classes with Strings using GWT.create()?
Its not possible according to many GWT forum posts but how is it being done in frameworks like Rocket-GWT (http://code.google.com/p/rocket-gwt/wiki/Ioc) and Gwittir (http://code.google.com/p/gwittir/wiki/Introspection)
It is possible, albeit tricky. Here are the gory details:
If you only think as GWT as a straight Java to JS, it would not work. However, if you consider Generators - Special classes with your GWT compiler Compiles and Executes during compilation, it is possible. Thus, you can generate java source while even compiling.
I had this need today - Our system deals with Dynamic resources off a Service, ending into a String and a need for a class. Here is the solutuion I've came up with - btw, it works under hosted, IE and Firefox.
Create a GWT Module declaring:
A source path
A Generator (which should be kept OUTSIDE the package of the GWT Module source path)
An interface replacement (it will inject the Generated class instead of the interface)
Inside that package, create a Marker interface (i call that Constructable). The Generator will lookup for that Marker
Create a base abstract class to hold that factory. I do this in order to ease on the generated source code
Declare that module inheriting on your Application.gwt.xml
Some notes:
Key to understanding is around the concept of generators;
In order to ease, the Abstract base class came in handy.
Also, understand that there is name mandling into the generated .js source and even the generated Java source
Remember the Generator outputs java files
GWT.create needs some reference to the .class file. Your generator output might do that, as long as it is referenced somehow from your application (check Application.gwt.xml inherits your module, which also replaces an interface with the generator your Application.gwt.xml declares)
Wrap the GWT.create call inside a factory method/singleton, and also under GWT.isClient()
It is a very good idea to also wrap your code-class-loading-calls around a GWT.runAsync, as it might need to trigger a module load. This is VERY important.
I hope to post the source code soon. Cross your fingers. :)
Brian,
The problem is GWT.create doen't know how to pick up the right implementation for your abstract class
I had the similar problem with the new GWT MVP coding style
( see GWT MVP documentation )
When I called:
ClientFactory clientFactory = GWT.create(ClientFactory.class);
I was getting the same error:
Deferred binding result type 'com.test.mywebapp.client.ClientFactory' should not be abstract
All I had to do was to go add the following lines to my MyWebapp.gwt.xml file:
<!-- Use ClientFactoryImpl by default -->
<replace-with class="com.test.mywebapp.client.ClientFactoryImpl">
<when-type-is class="com.test.mywebapp.client.ClientFactory"/>
</replace-with>
Then it works like a charm
I ran into this today and figured out a solution. The questioner is essentially wanting to write a method such as:
public <T extends MyInterface> T create(Class<T> clz) {
return (T)GWT.create(clz);
}
Here MyInterface is simply a marker interface to define the range of classes I want to be able to dynamically generate. If you try to code the above, you will get an error. The trick is to define an "instantiator" such as:
public interface Instantiator {
public <T extends MyInterface> T create(Class<T> clz);
}
Now define a GWT deferred binding generator that returns an instance of the above. In the generator, query the TypeOracle to get all types of MyInterface and generate implementations for them just as you would for any other type:
e.g:
public class InstantiatorGenerator extends Generator {
public String generate(...) {
TypeOracle typeOracle = context.getTypeOracle();
JClassType myTYpe= typeOracle.findType(MyInterface.class.getName());
JClassType[] types = typeOracle.getTypes();
List<JClassType> myInterfaceTypes = Collections.createArrayList();
// Collect all my interface types.
for (JClassType type : types) {
if (type.isInterface() != null && type.isAssignableTo(myType)
&& type.equals(myType) == false) {
myInterfaceTypes.add(type);
}
for (JClassType nestedType : type.getNestedTypes()) {
if (nestedType.isInterface() != null && nestedType.isAssignableTo(myType)
&& nestedType.equals(myTYpe) == false) {
myInterfaceTypes.add(nestedType);
}
}
}
for (JClassType jClassType : myInterfaceTypes) {
MyInterfaceGenerator generator = new MyInterfaceGenerator();
generator.generate(logger, context, jClassType.getQualifiedSourceName());
}
}
// Other instantiator generation code for if () else if () .. constructs as
// explained below.
}
The MyIntefaceGenerator class is just like any other deferred binding generator. Except you call it directly within the above generator instead of via GWT.create. Once the generation of all known sub-types of MyInterface is done (when generating sub-types of MyInterface in the generator, make sure to make the classname have a unique pattern, such as MyInterface.class.getName() + "_MySpecialImpl"), simply create the Instantiator by again iterating through all known subtypes of MyInterface and creating a bunch of
if (clz.getName().equals(MySpecialDerivativeOfMyInterface)) { return (T) new MySpecialDerivativeOfMyInterface_MySpecialImpl();}
style of code. Lastly throw an exception so you can return a value in all cases.
Now where you'd call GWT.create(clz); instead do the following:
private static final Instantiator instantiator = GWT.create(Instantiator.class);
...
return instantiator.create(clz);
Also note that in your GWT module xml, you'll only define a generator for Instantiator, not for MyInterface generators:
<generate-with class="package.rebind.InstantiatorGenerator">
<when-type-assignable class="package.impl.Instantiator" />
</generate-with>
Bingo!
What exactly is the question - i am guessing you wish to pass parameters in addition to the class literal to a generator.
As you probably already know the class literal passed to GWT.create() is mostly a selector so that GWT can pick and execute a generator which in the end spits out a class. The easist way to pass a parameter to the generator is to use annotations in an interface and pass the interface.class to GWT.create(). Note of course the interface/class must extend the class literal passed into GWT.create().
class Selector{
}
#Annotation("string parameter...")
class WithParameter extends Selector{}
Selector instance = GWT.create( WithParameter.class )
Everything is possible..although may be difficult or even useless. As Jan has mentioned you should use a generator to do that. Basically you can create your interface the generator code which takes that interface and compile at creation time and gives you back the instance. An example could be:
//A marker interface
public interface Instantiable {
}
//What you will put in GWT.create
public interface ReflectionService {
public Instantiable newInstance(String className);
}
//gwt.xml, basically when GWT.create finds reflectionservice, use reflection generator
<generate-with class="...ReflectionGenerator" >
<when-type-assignable class="...ReflectionService" />
</generate-with>
//In not a client package
public class ReflectionGenerator extends Generator{
...
}
//A class you may instantiate
public class foo implements Instantiable{
}
//And in this way
ReflectionService service = GWT.create(ReflectionService.class);
service.newInstance("foo");
All you need to know is how to do the generator. I may tell you that at the end what you do in the generator is to create Java code in this fashion:
if ("clase1".equals(className)) return new clase1();
else if ("clase2".equals(className)) return new clase2();
...
At the final I thought, common I can do that by hand in a kind of InstanceFactory...
Best Regards
I was able to do what I think you're trying to do which is load a class and bind it to an event dynamically; I used a Generator to dynamically link the class to the event. I don't recommend it but here's an example if it helps:
http://francisshanahan.com/index.php/2010/a-simple-gwt-generator-example/
Not having looked through the code of rocket/gwittir (which you ought to do if you want to find out how they did it, it is opensource after all), i can only guess that they employ deferred binding in such a way that during compile time, they work out all calls to reflection, and statically generate all the code required to implement those call. So during run-time, you cant do different ones.
What you're trying to do is not possible in GWT.
While GWT does a good job of emulating Java at compile time the runtime is of course completely different. Most reflection is unsupported and it is not possible to generate or dynamically load classes at runtime.
I had a brief look into code for Gwittir and I think they are doing their "reflection stuff" at compile time. Here: http://code.google.com/p/gwittir/source/browse/trunk/gwittir-core/src/main/java/com/totsp/gwittir/rebind/beans/IntrospectorGenerator.java
You might be able to avoid the whole issue by doing it on the server side. Say with a service
witch takes String and returns some sort of a serializable super type.
On the server side you can do
return (MySerializableType)Class.forName("className").newInstance();
Depending on your circumstances it might not be a big performance bottleneck.
I have java class with protected static method:
package parent;
public class Parent {
protected static void parentMethod() {
System.out.println("I'm in parent static method");
}
}
Before Scala 2.12.4 (2.12.3) I could call this method from another package like this:
package child
import parent.Parent
class Child extends Parent {
def childMethod = {
println("I'm in child method and calling parentMethod")
Parent.parentMethod()
}
}
But Scala 2.12.4 does not compile this code. I'm getting the error:
Error:(9, 12) method parentMethod in object Parent cannot be accessed
in object parent.Parent Access to protected method parentMethod not
permitted because prefix type parent.Parent.type does not conform to
object Child in package child where the access takes place
Parent.parentMethod()
This access pattern was very important for me because JOOQ code generation uses this.
What happened?
Nice catch, this is most likely a regression introduced by this PR, as part of a solution to this issue.
I've already opened a ticket for this that you can track. In the meanwhile, if this kind of access pattern is vital for your application, unfortunately I don't think you have much choice but to stick to Scala 2.12.3 for the time being.
Edit
The issue was already known and a fix has been already merged. As of the time of writing the patch is bound to be part of the 2.12.5 release.