I'm trying to figure out how to resolve the following use case:
A user can define a Java class, say MyFoo like this (the code is generated automatically and the guid is set to avoid name collisions)
import com.bar.entities.BaseEntity;
package com.bar.entities.defined.79B35635_DEDF_A344_9621_0477A6E71725;
public class MyFoo extends BaseEntity {
public String getFoo() { ... }
public Integer getBar() { ... }
#Override
public byte[] serialize() {...}
}
A user can import that Java class in other class like this:
package com.bar.business;
import com.bar.entities.defined.79B35635_DEDF_A344_9621_0477A6E71725.MyFoo;
public class Business extends Minion {
#Override
public void execute(EntityProvider ep) {
MyFoo myFoo = ep.get("myFoo", MyFoo.class);
if (myFoo.getBar() < 10) {
notifyMaster();
}
}
}
Additionaly I have a Java application (actually a Grizzly HTTP Server with a Jersey API Rest) that must be able to compile both classes.
¿How can I compile both classes? The first one can be compiled. The second one can't because the compiler says that the method getBar() is not known (it does not fail at the import line, surpringsly)
I want to send both Class<?> instances over the network and use them elsewhere via reflection with getDeclaredConstructor()
Kind regards.
Related
import java.util.*;
import java.lang.*;
import java.io.*;
class mainA {
private mainA obj;
public mainA(int type) {
System.out.println("accessing mainA");
switch(type) {
case 1:
obj = new mysql();
break;
case 2:
obj = new mssql();
break;
default:
break;
}
}
}
class mysql extends mainA {
public void printme() {
System.out.println("accessing mysql");
}
}
class mssql extends mainA {
public void printme() {
System.out.println("accessing mssql");
}
}
class C2 extends mainA {
public C2() {
super();
}
public static void main(String args[]){
Object b = new C2();
b.printme();
}
}
I need to achieve the following scenario. It would be great if someone can help me out.
I'm trying to create a common API library set which can be scaled to as many backend databases as possible.
The idea is to create an object of C2, which in turn would return the value of either mysql/mssql based on the dbtype. The type parameter can be obtained from any where in the code. mainA is the super class which consists of config params. Type can be obtained here as well. The problem here is that I'm stuck with not being able to get the object of mysql/mssql from C2. The ideal situation would be to create an object of C2 which refers to mainA that gets the type and inits either mssql/mysql. C2.printme must call the db class which was specified in the type.
Would generic classes be of any help here?
you can have an instanceof test to cast the object but it is lame as you would have to change your code if you are adding a new type of DB object.
You can have a good interface and make the subclasses implement it so that you can call through your interface without caring about the actual implementation object.
Coding to Interface is what you should be doing.
You've got some work ahead of you. You'll want to read up on interfaces. In your example, you can do something like the following (it's a bit silly in the real world).
Let's call our interface Printable.java (by convention, starts with either the capital letter "I" or ends in "-ible", "able," etc). I wouldn't really call it Printable, but for the purpose of this example:
public interface Printable {
public void logDatabaseType();
}
Your parent class (we can make it abstract so that it cannot be created directly without an underlying implementation):
public abstract class Database implements Printable {
#Override
public void logDatabaseType() {
System.out.println("logDatabaseType()");
}
}
Your subclasses:
public class MySQL extends Database implements Printable {
#Override
public void logDatabaseType() {
System.out.println("Accessing MySQL");
}
}
public class MicrosoftSQL extends Database implements Printable {
#Override
public void logDatabaseType() {
System.out.println("Accessing MSSQL");
}
}
In your test class (you should try to get your feet wet with JUnit as early as possible):
public class DatabaseLogTest {
#Test
public void printDatabaseType() {
//programming by interface
Printable printable = new MySql();
printable.logDatabaseType();
printable = new MicrosoftSQL();
printable.logDatabaseType();
//then later you can do
//someMethod(printable);
//and the printable object will retain whatever was instantiated
//and someMethod will be blissfully ignorant of the actual implementation
}
}
#Override is important because it tells your IDE and the developer that you're overriding an implementation and the IDE will spit out errors if the implied contract is not met. You should have this whenever you're overriding.
You'd also want to use a logger (e.g., SLF4j over Log4J or logback) rather than System.out.println() method calls.
Suppose I have a simple class:
public class TestClass {
/*...*/
}
I created an aspect which injects new method to this class:
public aspect TestAspect {
public void TestClass.aspectMethod() {
/*...*/
}
}
Now, how can I check if TestClass has method added by TestAspect in runtime?
The simplest way would be to simply reflect on the class:
TestClass.class.getDeclaredMethod("aspectMethod")
which will throw NoSuchMethodException if it isn't there. Or if you have the bytes you could use a byte code visitor to check what methods exist in the byte code - but the reflective route would be less messing around.
Andy's answer is the correct one, I just want to answer your follow-up question from the comment:
Duck typing is not a Java feature, but if you use ITD in order to make the class implement an interface and then have an instance of your aspect-extended class you can use instanceof MyInterface in order to determine what you need to know. Other ways (also using reflection) are also available:
Interface with the method you want to add later via ITD:
package de.scrum_master.app;
public interface MyInterface {
void myMethod();
}
Sample driver application:
package de.scrum_master.app;
import java.lang.reflect.Type;
public class Application {
public static void main(String[] args) {
Application application = new Application();
// Use an instance
System.out.println(application instanceof MyInterface);
System.out.println(MyInterface.class.isInstance(application));
// Use the class
for (Type type : Application.class.getGenericInterfaces())
System.out.println(type);
for (Class<?> clazz : Application.class.getInterfaces())
System.out.println(clazz);
}
}
Aspect:
package de.scrum_master.aspect;
import de.scrum_master.app.Application;
import de.scrum_master.app.MyInterface;
public aspect MyAspect {
declare parents : Application implements MyInterface;
public void Application.myMethod() {}
}
Application output:
true
true
interface de.scrum_master.app.MyInterface
interface de.scrum_master.app.MyInterface
Say I am using a closed source java library with a known buggy class, say BuggyClass and this class is hardcoded throughout the rest of the library. So I would imagine that the java library looks something like this:
public class BuggyClass {
public T buggyMethod (...) {
// Buggy code here
}
}
with several other classes in the library that make use of this class:
public class Example {
private BuggyClass = new BuggyClass(); // No dependency injection possible
public Example (/* No way to pass in my own subclass of BuggyClass*/) {
// ...
}
}
etc...
Is there any hack, or workaround, possibly using the class loader so that I could subclass BuggyClass and get Example (and every other class in the library that has BuggyClass hardcoded in) to use my subclass?
You can't do a subclass, no, but you can write your own BuggyClass entirely and make sure it appears earlier in the classpath than the real one. I don't think it's documented, but the default classloader seems to typically use the first matching class it finds.
But obviously this is a Really Bad Option, so you want to exhaust every other avenue before trying to solve temporarily work around the underlying problem this way.
Example: Suppose we have this:
// The "buggy" class
package somepackage;
public class BuggyClass {
public String someMethod() {
return "I'm in the buggy class";
}
}
and this:
// Uses the "buggy" class
package somepackage;
public class BuggyClassUser {
public String useBuggyClass() {
BuggyClass c = new BuggyClass();
return c.someMethod();
}
}
compiled and the classes in buggy.jar. Then we have this test class:
import somepackage.*;
public class Test {
public static final void main(String[] args) {
BuggyClassUser u = new BuggyClassUser();
System.out.println(u.useBuggyClass());
}
}
If we run that (*nix format classpath):
java -cp .:buggy.jar Test
...we see
I'm in the buggy class
But if we create a somepackage directory and put this in it:
package somepackage;
public class BuggyClass {
public String someMethod() {
return "I'm in the fixed class"; // <== Difference here
}
}
...and compile that, since we have that in our classpath in front of the jar, this command:
java -cp .:buggy.jar Test
...now gives us this:
I'm in the fixed class
Again, this is very, very much a workaround, not a solution.
Considering a java application with a embedded X impl/jar file, for example com.test package.
and we cannot change and modify the jar file.
Now suppose I have a X1.jar file which is modified version of exist X(com.test) package.
Question:
Is it possible to override the X1.jar implementation with embedded(exist) implementation just before the library gets loaded? and again, assume we cannot change the package anyway.
I'd like that to redirect all the types under com.test package to the new one.
Thanks in advance.
As per m0skit0's suggestion:
Orig class:
package example.x
public class SomeClass
{
public SomeClass(String neededVar)
{...}
public String someMethod(String someVar)
{
// original implementation
}
}
Custom class:
import example.x.SomeClass
public class MySomeClass extends SomeClass
{
public MySomeClass(String neededVar)
{
super(neededVar);
// anything else
}
#Override
public String someMethod(String someVar)
{
// implement differently
super.someMethod(someVar);
// or add to it
}
}
My issue seems to be similar to this question and this one but it is a bit different.
I am making an AIDL service that is in a Library project and using it in my application. I have a class Vehicle that is in my application that I have made parcelable so that I can use it in my interface. (I would like to get a List of vehicles from my service that is in the library to my application)
Do I need a Vehicle.java in both the application and the library?
Do I need a Vehicle.aidl in both?
I had Vehicle.java AND Vehicle.aidl in both application and library and I began running into a problem in my application that when I called a method from my interface eclipse wanted me to define it as the Vehicle of the library class and not the application(although they are the same and both parcelable).
public List<Vehicle> getVehicles(){...code... }
In an effort to resolve this, I tried to make it the application's vehicle class rather than the library's vehicle class in my IRemoteInterface.aidl(in the listed variation below, i get an error that it can't find the import. In other variations like having it be List and no import, it says unknown return type).
package LIBRARY;
import LIBRARY.RelPoint;
import LIBRARY.IRemoteServiceCallback;
import LIBRARY.FleetStatus;
import APPLICATION.Vehicle;
interface IRemoteInterface {
int getPid();
void registerCallback(IRemoteServiceCallback callback);
void unregisterCallback(IRemoteServiceCallback callback);
List<Vehicle> getVehicles();
}
Here is my parcelable Vehicle class from the application :
package APPLICATION;
import java.util.Date;
import android.os.Parcel;
import android.os.Parcelable;
public class Vehicle implements Parcelable {
public static final String TAG = "Vehicle";
long vehicleID;
long trackID;
String vehicleName;
public static final Parcelable.Creator<Vehicle> CREATOR = new Parcelable.Creator<Vehicle>() {
public Vehicle createFromParcel(Parcel src) {
return new Vehicle(src);
}
public Vehicle[] newArray(int size) {
return new Vehicle[size];
}
};
public Vehicle(Parcel src) {
readFromParcel(src);
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(vehicleID);
dest.writeLong(trackID);
dest.writeString(vehicleName);
}
public void readFromParcel(Parcel src) {
vehicleID = src.readLong();
trackID = src.readLong();
vehicleName = src.readString();
}
public int describeContents() {
// nothing special
return 0;
}
public Vehicle() {
}
//getter and setter methods below that I removed
}
I'm reasonably certain you need to have the Parcelable classes in the same package on both ends (which is what you end up with by using the one from APPLICATION on the library side, I would just do it the other way around). This package has to also be the one declared in the corresponding aidl file.
I'd suggest to use a subpackage like com.example.interop to make this cleaner (i.e., separate the shared objects in their own package). Both sides should then have a Java file in that package + an aidl file that declares it.
I had the same issue and got it working with the following folder and file structure:
Under src/main create a directory named "aidl". This is where Android by default looks for .aidl files
Under "aidl/" create a directory "com/mypackage/util"
Then under "src/main/aidl/com/mypackage/util" put the .aidl file of your service and a separate .aidl file of your Parcelable. If the service is called IGetCards then the aidl file must be named IGetCards.aidl and if you Parcelable is called Cards then it must be in its own file named Cards.aidl.
In src/main/aidl/com/mypackage/util/IGetCards.aidl:
package com.mypackage.util;
import com.mypackage.util.Cards;
/** Example service interface */
interface IGetCards {
/** Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
Cards getCards();
}
In src/main/aidl/com/mypackage/util/Cards.aidl:
package com.mypackage.util;
parcelable Cards;
Check each file has a package statement at the top and that the service file IGetCards has an import statement at the top importing the Cards class.
Now in the Java directory src/main/java/com/mypackage/util, put a corresponding Cards.kt file which implements the interface. Make sure Cards.kt has a package statement at the top that matches Cards.aidl.
In src/main/java/com/mypackage/util/Cards.kt:
package com.mypackage.util;
class Cards() : Parcelable {
//implement members
...
}