Java lazy instantation using inversion of control container - java

I have this container:
public class DIContainer {
protected static DIContainer instance;
protected Hashtable<Class<?>, Class<?>> classMap;
protected DIContainer(){
this.classMap = new Hashtable<Class<?>, Class<?>>();
}
public static DIContainer getInstance(){
if (DIContainer.instance == null)
DIContainer.instance = new DIContainer();
return DIContainer.instance;
}
public void regClass(Class<?> interf, Class<?> classToReg){
this.classMap.put(interf, classToReg);
}
public Object create(Class<?> interf, boolean lazy) throws Exception{
if(!this.classMap.containsKey(interf))
throw new Exception("No such class registered with "+interf.getName()+" interface");
else if(lazy == false)
return this.classMap.get(interf).newInstance();
else
return this.classMap.get(interf);
}
}
And I need to lazy create an object, if lazy creation option is chosen (so it would create some sub-object that would implement same interface). So when first method would be called for that sub-object, it would instantiate 'real' object. How could I do it as I don't know exact method that would be used? How can I check for if any method was called for that object?
Now I only tried this as lazy creation as you can see:
return this.classMap.get(interf);
But it gives me an error: java.lang.ClassCastException
Do I need some other method to check if any call was made to that sub-object, because after creation is done, I will be out of 'create' method and when method will be called I need to check it somehow?
Here are my test interface and it's implementation class:
public interface Interface1 {
public String getName();
public void setName(String name);
}
public class Class1 implements Interface1{
String name;
Class1(){}
#Override
public String getName() {
return name;
}
#Override
public void setName(String name) {
this.name = name;
}
}
And this is how I test it:
public class Main {
public static void main(String[] args) throws Exception{
DIContainer dic = DIContainer.getInstance();
dic.regClass(Interface1.class, Class1.class);
Interface1 t1 = (Interface1) dic.create(Interface1.class, true);
P.S. If I set lazy creation to false, then it works.

In your case, the line return this.classMap.get(interf); returns a Class object, which you previously put inside the map with the this.classMap.put(interf, classToReg) line. The Class object definitely cannot be cast to the Interface1 interface, as it does not implement it, which results in the ClassCastException.
What you actually need is to return a kind of a wrapper that implements the Interface1 interface and wraps the lazily instantiated class. When any of the interface's method is called, the wrapper instantiates the actual object and delegates the call.
If you want to lazy-init an arbitrary class, the most straight forward option would be to use Java's dynamic proxy.

Related

Java - Given Interface with methods - how are parameters passed?

I tried to keep the code as generic as possible, this only represents
the basic setup. I am a Java beginner trying to understand Interfaces, Classes
and Methods. I did change the Interface name and Class names to make referencing
them easier. I am fully aware that this code as it is won't compile.
I am trying to understand the concept.
Given is an Interface, with an existing InterfaceClass and another class
using the interface.
Interface:
public interface IInterface extends Comparable<IInterface>{
String getContent() throws DumbException;
}
Class:
public class InterfaceClass implements IInterface{
public String getContent() throws DumbException {
// here I would need a parameter (filepath) to get a file
// and read its content and return the content as string
// however the interface doesn't provide a parameter for this
// method. So how is this done?
}
}
The class using the method:
public class Frame extends AbstractFrame {
public void setDetails(IInterface details) {
// This is the call I don't understand...
details.getContent();
}
}
The part I don't understand is:
How does the details object give any parameter to getContent()?
I mean I don't even see this object being defined other than IInterface details
Solution 1
You can redefine IInterface to
public interface IInterface extends Comparable<IInterface>{
String getContent(String filepath) throws DumbException;
}
public class InterfaceClass implements IInterface{
public String getContent(String filepath) throws DumbException {
// use filepath to get the file's content
}
}
Usage is
public class Frame extends AbstractFrame {
public void setDetails(IInterface details) {
details.getContent("/path/to/some/folder");
}
}
Solution 2
You can't change IInterface but you add a constructor to InterfaceClass
public class InterfaceClass implements IInterface{
private String filepath;
public InterfaceClass(String filepath) {
this.filepath = filepath;
}
public String getContent() throws DumbException {
// use filepath to get the file's content
}
}
Usage is
new Frame().setDetails(new InterfaceClass("path/to/some/folder"));
You can pass a data in constructor in base class
public class InterfaceClass implements IInterface{
private String data;
public InterfaceClass(String data) {
this.data = data;
}
public String getContent() throws DumbException {
//do something here with data
// here I would need a parameter (filepath) to get a file
// and read its content and return the content as string
// however the interface doesn't provide a parameter for this
// method. So how is this done?
}
}
You can use this class now:
IInterface myNewClass = new InterfaceClass("blablabla");
frameClass.setDetails(myNewClass);
And pass it to second class.
details is the argument passed to setDetails as type implementing IInterface. Anything that implements IInterface can be used as details, since the interface gives you contract assurance that getContent is in fact a strict member for that implementation.
public interface IInterface extends Comparable<IInterface>{
String getContent() throws DumbException;
}
public class InterfaceClass implements IInterface{
public String getContent() throws DumbException {//this method is of string type so you must provide return type
return "some details";
}
}
public class Frame extends AbstractFrame {
public void setDetails(IInterface details) {
System.out.println(details.getContent()); //output:- some details
}
}
public class SomeClass{
public void someMethod(){
new Frame().setDetails(new InterfaceClass)
}
}
Just pay note here to SomeClass. In SomeClass you are passing object of extended class i.e interfaceClass (and this is ploymorphism).
And like you did ,you need to pass object to interface variable like IInterface details=new InterfaceClass() or some any other class that implements IInterface but note that the class must extend thatIInterfaceand in your case it isinterfaceClass`
If you fail to that it will throw nullpointerExecption because it is just a reference variable , so you need to pass the object of actual class with that method and ploymorphism will handle rest.
note This is common way to access child classes and provides loose coupling and if you'll work on spring you'll know better.
Hope it helps

What is the proper design pattern to use when you have a bunch of extremely similar classes that can't share an interface?

I have an abstract class, called Base that handles a bunch of logic for handling some data I have. The API looks like this:
// Class has no abstract methods, but is uninstantiable
public abstract class Base {
private Param param;
protected Base() {}
protected void setParam(Param param) {
this.param = param
}
public void doThing() {
// Code here to do a common thing
}
public void doOtherThing() {
// Code here to do another common thing
}
protected void handle(Object... objects) {
// This code delegates work to a scripting language via the param
// It is not type safe and the array of objects needed will vary depending
// on the implementing class.
}
}
Of course, the weird thing here is the handle(Objects...) method. To show how it is used, look at one of the subclasses:
public class Person extends Base {
protected Person(Param param) {
super();
setParam(param);
}
public void handle(String name, int age) {
// Expose a type safe interface to the world
super.handle(name, age);
}
}
As you can see, the subclasses hide super.handle, which is protected, for certain arguments so that consumers of this class can have type safe interactions without passing around Arrays of objects. The problem is, I would like to create these from a factory that enforces having one instance of the subclass per param. Currently, this factory looks like this:
public class Factory {
Map<Param, Person> persons;
Map<Param, Other> others; // Other also extends Base
public Person getPerson(Param param) {
Person person = persons.get(param);
if (person == null) {
person = new Person(param);
persons.put(param, person);
}
return person;
}
public Other getOther(Param param) {
Other other = others.get(param);
if (other == null) {
other = new Other(param);
other.put(param, other);
}
return other;
}
}
Obviously, this sucks, but I can think of no better way to handle this case due the strange nature of interacting with a scripting language via the param, which relies on string construction to execute code. Does anyone have any guidance on how to clean up this design?
One could generalize the factory class, with some generics and reflection for instantiating at runtime a specific subclass type:
import java.util.HashMap;
import java.util.Map;
public class Factory<T> {
private Map<Param, T> instances = new HashMap<Param, T>();
public final T create(Class<T> clazz, Param param) throws Exception {
T cur = instances.get(param);
if (cur == null) {
cur = clazz.newInstance();
((Base)cur).setParam(param);
instances.put(param, cur);
}
return cur;
}
}
Subclasses should have the no-args constructor, not public; for consistency remove the with-param one:
public class Person extends Base {
protected Person(){}
public void handle(String name, int age) {
// Expose a type safe interface to the world
super.handle(name, age);
}
}
An example of usage:
public class TestFactory {
public static void main(String[] args) throws Exception {
Factory<Person> factory = new Factory<Person>();
Person p = factory.create(Person.class, new Param());
}
}
Of course I know this is not a pattern and it is not the more elegant code I could be proud of, but still avoid you having to change the factory for each new subclass, it does not use static methods and keeps in a single point the caching logic.

Java: Return an object that extends an abstract class which takes arguments

I've got an interface
public interface I
{
public AnAbstractClass k(); //Abstract Class constructor takes two arguments
}
For an implementation of this interface's method I want to return a generic object which extends that AbstractClass and also give it its two argument constructor
To clarify what I want to achieve. In a class which implements I:
public AnAbstractClass k()
{
//return a new implementing AbstractClass object AbstractClassObject(arg1,arg2)
}
Constructors are not inherited, so subclasses of AnAbstractClass won't necessarily have a two-argument constructor. If a subclass does have a two-argument constructor, there is nothing stopping you from creating an instance of that subclass using the two-argument constructor and returning it:
public abstract class AnAbstractClass
{
public AnAbstractClass(String foo, String bar) {
System.out.format("created with (%s, %s)\n", foo, bar);
}
}
public class BaseClass extends AnAbstractClass
{
public BaseClass(String foo, String bar) {
super(foo, bar);
}
}
public interface I
{
public AnAbstractClass k();
}
public class Implementation implements I
{
#Override public AnAbstractClass k() {
return new BaseClass("hello", "world");
}
}
public class Demo
{
public static void main(String[] args) {
I i = new Implementation();
AnAbstractClass a = i.k();
}
}
There are sophisticated solutions for this problem (roughly: Everything that is related to dependency injection). However, in this case, there are not so many options: Someone HAS to provide these arguments, and they obviously can not be passed to the interface method. So you'll probably need something like
class Creator implements I
{
private Object arg0;
private Object arg1;
void setArgs(Object arg0, Object arg1)
{
this.arg0 = arg0;
this.arg1 = arg1;
}
#Override
public AnAbstractClass k()
{
return new ConcreteClassExtendingAnAbstractClass(arg0, arg1);
}
}
The drawback is that this interface might become more or less useless: If it was designed to be a factory, you can no longer use it in its abstract form...
I i = obtainFromSomewhere();
AnAbstractClass a = i.k();
but you always have to know the particular type
Creator i = obtainFromSomewhere();
i.setArgs(..., ...);
AnAbstractClass a = i.k();

Can a custom class know the name of the object that called it?

Is there anyway, when calling a method through an object (instance) for that method to know which instance (object) called it?
Here's an example (pseudo code) of what I mean:
Pseudo code example
public class CustomClass{
public void myMethod(){
if (calling method is object1){
//Do something here
}
else {
//Do something else
}
}//End of method
}//End of class
And then in another class:
public SomeOtherClass{
CustomClass = object1;
public void someOtherMethod(){
object1 = new CustomClass();
object1.myMethod(); //This will call the 1st condition as the calling object is object1, if it were some other object name, it would call the 2nd condition.
}//End of method
}//End of class
Possible work-around
The only way I've found to do this is to get the method to take another argument, say an 'int' and then check the value of that int and perform whichever part of the 'if else' statement relates to it (or 'switch' statement if definitely using an 'int' value) but that just seems a really messy way of doing it.
What you need is the Strategy Pattern
public abstract class CustomClass {
public abstract void MyMethod();
}
public class Impl1 extends CustomClass {
#Override
public void MyMethod() {
// Do something
}
}
public class Impl2 extends CustomClass {
#Override
public void MyMethod() {
// Do something else
}
}
Use it this way
public static void main(String[] args) {
CustomClass myObject = new Impl1();
// or CustomClass myObject = new Impl2();
}
As your comment says what you really need is perhaps the Template method Pattern
public abstract class CustomClass {
public void myMethod(){ // this is the template method
// The common things
theDifferentThings();
}
public abstract void theDifferentThings();
}
public class Impl1 extends CustomClass {
#Override
public void theDifferentThings() {
// Do something
}
}
public class Impl2 extends CustomClass {
#Override
public void theDifferentThings() {
// Do something else
}
}
You can know the name of current class by calling getClass().getName(). However you cannot know the name of object, moreover this does not have any meaning:
MyClass myObject1 = new MyClass();
MyClass myObject2 = myObject1;
myObject1.foo();
myObject2.foo();
Do you wutant foo() to know that it was invoked using myObject1 or myObject1? But both references refer to the same object!
OK, there are extremely complicated ways to know this. You can use byte code engineering using one of popular libraries like javassist, ASM, CGLib and inject missing information about the "object name" into byte code and then read this information. But IMHO this is not what you need.
You can define a new attribute inside CustomClass which will store the identifier of the instance. If there will be only a few instances of CustomClass then you can use an enum type.
Replace:
object1 = new CustomClass();
with:
object1 = new CustomClass(1);
Add a new constructor and an attribute to CustomClass:
private int id;
public CustomClass(int id) {
this.id = id;
}
Then you can replace:
if (calling method is object1){
with:
if (id == 1){
However, please keep in mind that this is a bad design.
You should not have if conditions differing logic depending on the instance which called this method. You should should use polymorphism for such purpose.

Why java.lang.Object can not be cloned?

When i try to clone a generic Object i get compile time error . why?
Object obj=new Object();
obj.clone(); // Here compile time error "The method clone() from the type Object is not visible"
Every class extends Object class and clone method is protected in Object class.
protected methods can be accessed in same package as well as by subclasses and all classes are child of java.lang.Object.
Because clone is protected in the Object class. It's not public.
The only way to get access to an object's clone() method is to know it has a compile-time type that has a public clone() method.
This will be the minimum to get clone working:
public class SubObj implements Cloneable {
public Object clone() { return super.clone(); }
}
Per the Java SE docs:
The class Object does not itself implement the interface Cloneable, so
calling the clone method on an object whose class is Object will
result in throwing an exception at run time.
protected fields can be accessed only from inside the same package, thus clone() method of Object class can be accessed only from any class that is located in java.lang package.
You must explicitely implements Cloneable interface.
see this thread which give explanations.
If you use Groovy so that you can bypass the java compilation error, you get this:
Exception in thread "main" java.lang.CloneNotSupportedException: java.lang.Object
at java.lang.Object.clone(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:230)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:912)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:756)
at org.codehaus.groovy.runtime.InvokerHelper.invokePojoMethod(InvokerHelper.java:766)
at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:754)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:170)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethod0(ScriptBytecodeAdapter.java:198)
at regexTests.main(regexTests.groovy:19)
ERROR: JDWP Unable to get JNI 1.2 environment, jvm->GetEnv() return code = -2
JDWP exit error AGENT_ERROR_NO_JNI_ENV(183): [../../../src/share/back/util.c:820]
If you read the clone API (I will link it) it says that if the Interface isn't implemented, then calling *.clone() will throw a CloneNotSupportedException.
Link to the clone API for java.lang.Object
http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#clone%28%29
[EDIT]
The Original Question™ asked for why this method is visible in the way it is. This is because it only accessible to methods within the java.lang package. It isn't intended for a programmer to be able to clone an Object. Throwing a CloneNotSupportedException is exactly what you want to do if you don't want your OWN object cloned.
void method() {
Object obj=new Object(); //Object is a parent class, it's not inherit from any other class...
obj.clone(); // compile time error
}
We can't access the protected method of "Has A" relationship from different package, because your Class package is (com.xxx.yyy) and an Object class package is (java.lang) both the classes are in different package.
protected methods can be accessed in same package as well as by subclasses(IS A relationship)
I tried this code :
public final class User {
private String name;
private boolean isActive;
private String userId;
private Address address;
// can be constructed using this constructor ONLY !
public User(String name, boolean isActive, String userId, Address address) {
this.name = name;
this.isActive = isActive;
this.userId = userId;
this.address = address;
}
public String getName() {
return name;
}
public boolean isActive() {
return isActive;
}
public String getUserId() {
return userId;
}
public Address getAddress() {
return address;
}
protected Object cloneMe() throws CloneNotSupportedException {
return super.clone(); // throws CloneNotSupportedException
}
}
public class CloneNotSupportedException
extends Exception
Thrown to indicate that the clone method in class Object has been
called to clone an object, but that the object's class does not
implement the Cloneable interface. Applications that override the
clone method can also throw this exception to indicate that an object
could not or should not be cloned.
Object doesn't implement any interface and to make my User class work it must implement Cloneable
Object class clone() method has modified by protected access modifier in the API level. So we can't access it anywhere without inheritance. So before we invoke object class clone() method you need to implements Cloneable interface. Then Code will run at runtime properly. Otherwise it will generate CloneNotSupportedException at runtime.
/*Subclass is my implementing class */
public class SubClass implements Cloneable {
#Override
public SubClass clone() throws CloneNotSupportedException {
return (SubClass) super.clone();
}
}
import java.util.Scanner;
import java.util.jar.Attributes.Name;
import java.util.Arrays;
public class Main{
public class man{
protected void name() {
System.out.println("hei");
}
}
public class people extends man{
public int age;
public int getAge() {
name();
return age;
}
public void setAge(int age) {
this.age = age;
}
#Override
public String toString() {
return "people [age=" + age + "]";
}
public Object myclone() throws CloneNotSupportedException {
return this.clone();
}
}
public void test() throws CloneNotSupportedException {
people p1 = new people();
p1.setAge(10);
System.out.println(p1);
// NG:
people p2 = (people)p1.clone();
// Ok
people p3 = (people)p1.myclone();
p1.setAge(10);
System.out.println(p1);
System.out.println(p2);
}
public static void main(String args[]) throws CloneNotSupportedException{
new Main().test();
}
}
see the NG code and ok code.
// NG for:The method clone() from the type Object is not visible
people p2 = (people)p1.clone();
// Ok
people p3 = (people)p1.myclone();
why?
cause test() is not belong to the subclass.
so even though call clone() by peopel object p1,it is not the place of peopel object.
The myclone() is the exactly the place of people object.

Categories

Resources