How can i create instance conditionally(by string) in Java? - java

I'm trying to create(initiate) instance conditionally.
I have an interface and there are several classes which implement the interface.
(e.g. interface named "itfc" and there class "classA", "classB", "classC"
when I get a string from outside, (e.g. "a") then I wanna make class of A
so, it can be written like this:
public class someClass {
itfc interface;
public someClass(String name) {
this.inteface = makeInstanceByName(name);
}
public makeInstanceByName(name) {
if (name == "A") { return new classA(); }
else if (name == "B") { return new classB(); }
...
else { return null; }
}
}
but I have lots of classes which implements the interface, and also this codes don't look good.
I've searched the enums, but I don't know how to apply it into my one.
Can you help me?

Try class.forName(String), e.g. something like
Class.forName("my.package.name.ClassPrefix" + name)
Also make sure you take care of proper exception handling.
Update: Here is a complete MCVE as a proof of concept which also shows you how to instantiate the class via reflection API. But in this case you need to make sure that each target class has a default (no-arguments) constructor.
package de.scrum_master.app;
public interface MyInterface {}
package de.scrum_master.app;
public class Foo implements MyInterface {}
package de.scrum_master.app;
public class Bar implements MyInterface {}
package de.scrum_master.app;
public class Zot implements MyInterface {}
package de.scrum_master.app;
public class UhOh /*implements MyInterface*/ {}
package de.scrum_master.app;
public class Application {
public static void main(String[] argv) throws Exception {
System.out.println(makeInstanceByName("Foo"));
System.out.println(makeInstanceByName("Bar"));
System.out.println(makeInstanceByName("Zot"));
System.out.println(makeInstanceByName("UhOh"));
}
public static MyInterface makeInstanceByName(String name) throws Exception {
return
(MyInterface) Class.forName("de.scrum_master.app." + name)
.getConstructor()
.newInstance();
}
}
Console log:
de.scrum_master.app.Foo#6d06d69c
de.scrum_master.app.Bar#7852e922
de.scrum_master.app.Zot#4e25154f
Exception in thread "main" java.lang.ClassCastException: de.scrum_master.app.UhOh cannot be cast to de.scrum_master.app.MyInterface
at de.scrum_master.app.Application.makeInstanceByName(Application.java:15)
at de.scrum_master.app.Application.main(Application.java:8)

Related

Lambda does not override an interface method from a separate file

When the functional interface is in the same file where lambda overrides it, it compiles fine.
package test.test;
public class Base {
public static void main(String[] args) {
Interface1 a = n -> System.out.println(2*n);
}
}
interface Interface1 {
void multiplyByTwo(int x);
}
When the functional interface is in a separate file and Base class implements it, it fails to compile with Base is not abstract and does not override abstract method multiplyByFour(int) in Interface3 error.
package test.test;
public class Base implements Interface3 {
public static void main(String[] args) {
Interface3 b = n -> System.out.println(4*n);
}
}
package test.test;
public interface Interface3 {
void multiplyByFour(int x);
}
Is here something wrong? Why does lambda not override the method in the second case?
Your first example has:
public class Base {
which does not implement Interface1
However, your second example has:
public class Base implements Interface3 {
which DOES implement Interface3
Not sure what you are trying to do here, but this is intended behaviour:
Interfaces
When a class implements an interface, you must implement all of the methods into the class
For example:
public interface IFoo {
void bar();
}
and class:
public class FooImpl implements IFoo {
// must implement bar method in IFoo
public void bar() {
System.out.println("I did something");
}
}
Having a lambda in the main method does not constitute implementing interface methods.
Fix?
Just delete implements Interface3, you don't need to implement the interface in your class to be able to use it.

Avoid a class to be extend anonymously in Java

In Java, is it possible to prevent a class for being extended anonymously?
For example
public class A () {
public void hello() {}
}
I want to allow a named class extension:
public class B extends A {
}
but not anonymously:
A a = new A() {
public void hello() {
}
}
This is for serialization purpose.
Yes, there is a way to accomplish this, through the use of a runtime exception:
class MyData implements Serializable {
public MyData() {
if (getClass().isAnonymousClass()) {
throw new IllegalStateException("Anonymous subclasses are not serializable.");
}
}
}
Technically, anonymous classes are serializable, but it might be a good idea taking a look at this before trying to live with that.

Class(implementing the interface) and interface in same file and accessing the class from a main class in different package

I was going through some design pattern videos on YouTube, however I have a small doubt on some basic Java concept. I tried searching for solution, but was unable to find one. Below is my query.
I have some classes Animal.java, Dog.java, an interface Fly.java which also has a class named CantFly in same file. A main method CheckAnimal.java. Below is the code
Animal.java
package com.classification.pojo;
public class Animal {
public Fly flyingType;
public String tryToFly() {
return flyingType.fly();
}
public void setFlyingAbility(Fly newFlyType) {
flyingType = newFlyType;
}
}
Dog.java
package com.classification.pojo;
public class Dog extends Animal {
public Dog() {
super();
flyingType = new CantFly();
}
public void digHole() {
System.out.println("I am digging hole!");
}
}
Fly.java
package com.designpattern.strategy;
public interface Fly {
String fly();
}
class CantFly implements Fly {
public String fly() {
return "Can't fly";
}
}
class ItFlys implements Fly {
public String fly() {
return "I can fly";
}
}
CheckAnimal.java
package com.designpattern.main;
import com.classification.pojo.Animal;
import com.classification.pojo.Dog;
import com.classification.pojo.Fly;
public class CheckAnimals {
public static void main(String[] args) {
Animal doggy = new Dog();
System.out.println(doggy.tryToFly());
doggy.setFlyingAbility(new ItFlys());
System.out.println(doggy.tryToFly());
}
}
In CheckAnimal.java, for doggy object to invoke setFlyingAbility() method correctly, Animal.java, Dog.java and Fly.java needs to be in same package. If I keep Fly.java in different package, I cannot access CantFly() constructor. I hope I have made my point clear.
-
Ishan
You've declared CantFly without any access modifier:
class CantFly
... which means it's only accessible within the same package. Just make it public, and then you'll be able to use it within other packages. See the Java tutorial on access modifiers for more information. The same is true for the ItFlys class.
Additionally, you haven't imported the right package in your CheckAnimal.java file. You should be importing com.designpattern.strategy.ItFlys. You don't need to import Fly at all in CheckAnimal.java, as you're never referring to that interface directly in that file.
That's right. You can make the CantFly class public to access it outside of it's package, but note that doing that requires you to put it in its own file.
That is: Create CantFly.java with the following content:
package whatever.package.you.want;
import com.designpattern.strategy.Fly;
class CantFly implements Fly {
public String fly() {
return "Can't fly";
}
}
Also, it shouldn't be new Fly.CantFly() (since you haven't defined CantFly inside the Fly interface). It should be just new CantFly().
If you really want to keep Fly and CantFly in the same file, you can let CantFly be an inner class:
interface Fly {
...
class CantFly {
...
}
}
and then instantiate it with new Fly.CantFly(). If you're fine with this, I'd probably recommend you to consider using an enum instead:
enum FlyCapability {
CANT_FLY {
#Override
public String fly() {
return "Can't fly";
}
},
CAN_FLY {
#Override
public String fly() {
return "Can fly";
}
};
public abstract String fly();
}
First Of all Fly is an interface that cannot be instantiate which you are doing in CheckAnimal class.
Try this:-
package com.designpattern.main;
import com.classification.pojo.Animal;
import com.classification.pojo.Dog;
import com.classification.pojo.Fly;
public class CheckAnimals {
public static void main(String[] args) {
Animal doggy = new Dog();
doggy.setFlyingAbility(new CantFly());
}
}
and CantFly is no a method it is a class.
This is because the default modifier of a class is package-private, meaning it is visible only by classes in the same package.
You can simply make CantFly a public class defined in its own Java file.
CantFly is not nested inside the Fly interface, so you would need to call its constructor using new CantFly() instead of new Fly.CantFly().

Annotate class with inner class

I create my enums through reflection, for that I add to each enum an inner class which implements the abstract factory. Now I want to access this inner class in order to invoke the method:
#Factory(FooFactory.class)
public enum Foo {
FOO, BAR;
public class FooFactory implements AbstractFactory<Foo> {
public Foo create(String value) {
return valueOf(value.toUpperCase());
}
}
}
The definition of #Factory is:
#Retention(RetentionPolicy.RUNTIME)
public #interface Factory {
Class<?> value();
}
With this, however, I receive the following error:
Class cannot be resolved to a type FooFactory.java
When I try #Factory(Foo$FooFactory.class) I receive the error:
The nested Foo$FooFactory cannot be referneced using its binary name.
So is it even possible to reference a nested class?
From the comments... apparently
#Factory(Foo.FooFactory.class)
was needed.
You're using a non-static nested class, which is scoped to the individual instances of the enum.
Instead, you need a static nested class, like so:
public static class FooFactory implements AbstractFactory<Foo> {
public static Foo create(String value) {
return valueOf(value.toUpperCase());
}
}
However, all of this is redundant: you can simply call Foo.valueOf(value) to achieve this goal. I don't see any value added here (no pun intended).
Factory.java
import java.lang.annotation.*;
#Retention(RetentionPolicy.RUNTIME)
public #interface Factory {
Class<?> value();
}
FooEnum.java
#Factory(FooEnum.FooFactory.class)
public enum FooEnum {
FOO, BAR;
public static class FooFactory {
public static FooEnum create(String value) {
return valueOf(value.toUpperCase());
}
}
}
FooEnumMain.java
public class FooEnumMain {
public static void main(String[] args) {
FooEnum f = FooEnum.FooFactory.create("foo");
System.out.println(f);
}
}
At the point when your annotation is presented, FooFactory is undefined, so the full path needs to be specified:
#Factory(Foo.FooFactory.class)

mocking abstract classes [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Using Mockito to test abstract classes
I have an abstract class with functionality I need to test. I could create simple derivative of that class with no op implementations of abstract methods, but is it possible to be done with mocking framework? I need to maintain class internal state, so I can't just call
mockedInstance = mock(ClassUnderTest.class);
I need something
mockedInstance = spy(new ClassUnderTest(...));
but apparently this is impossible to do as class is abstract.
When I want to unit test an Abstract class I don't mock, I subclass.
borrowing code from mijer in other answer
public class MockitoTest {
public static abstract class MyAbstractClass {
private int state;
public abstract int abstractMethod();
public int method(....)
{
...
}
}
}
class Testclass extends MyAbstractClass
{
public int abstractMethod()
{
...
}
}
Then run your tests of MyAbstractClass using an instance of Testclass.
you can control the implementation of the abstract methods in your local subclass.
import org.junit.Test;
import org.mockito.internal.stubbing.answers.CallsRealMethods;
import static org.mockito.Mockito.*;
import static org.junit.Assert.*;
public class MockitoTest {
public static abstract class MyAbstractClass {
private int state;
public abstract int abstractMethod();
public void method() {
System.out.println("method. State: " + (++state));
System.out.println("abstractMethod: " + abstractMethod());
anotherMethod();
}
public void anotherMethod() {
System.out.println("anotherMethod. State: " + (++state));
}
}
#Test
public void test() throws Exception {
MyAbstractClass obj = mock(MyAbstractClass.class, new CallsRealMethods());
doReturn(5).when(obj).abstractMethod();
obj.method();
verify(obj).abstractMethod();
assertEquals(2, obj.state);
}
}
-EDIT-
If you need to maintain internal state of the object you have to use org.mockito.internal.util.reflection.Whitebox.setInternalState, for example:
#Test
public void test() throws Exception {
MyAbstractClass obj = mock(MyAbstractClass.class, new CallsRealMethods());
setInternalState(obj, "state", 100);
doReturn(5).when(obj).abstractMethod();
obj.method();
verify(obj).abstractMethod();
assertEquals(102, obj.state);
}
If you have an abstract class with a complex logic in its constructor which you would like to test, you should extend this class just for testing or refactor your class moving all the logic to some method to be tested.

Categories

Resources