How to provide new class instance within constructor in Spring? - java

I have a Spring managed class that extends a base service. I'd like to write the base service in a way that any implementation classes must provide a specific FileAnalyzer instance. But I don't want to make the FileAnalyzer class to be spring managed.
It that possible? Because a super() class always has to be the first call in a constructor, so I cannot instantiate any classes before invoking the base constructor.
Example:
public abstract class BaseService {
BaseService(FileAnalyzer analyzer, String path) {
this.path = path;
//perform any action with analyzer.
}
}
#Service
public class TextfileService {
public TextfileService() {
//ERROR: super() must be first call in constructor
FileAnalyzer analyzer = new FileAnalyzer();
analyzer.configure(..);
super(analyzer, "c:\logs");
}
}

It that possible? Because a super() class always has to be the first call in a constructor
Yes it's possible. Just move the code in a private static method and call it from inside the super() call.
#Service
public class TextfileService {
public TextfileService() {
super(getFileAnalyzer(), "c:\logs");
}
}
private static FileAnalyzer getFileAnalyzer(){
FileAnalyzer analyzer = new FileAnalyzer();
analyzer.configure(..);
return analyzer;
}
Alternative way:
If FileAnalyzer is your custom class written by you then just make a change in the return type of the method configure() as shown below:
#Service
public class TextfileService {
public TextfileService() {
super(new FileAnalyzer().configure(...), "c:\logs");
}
}
FileAnalyzer.java
public FileAnalyzer configure(){
...
return this;
}

You can use a lookup method injection.
Just assign a lookup method and it will be called whenever you instantiate a new object of this class.
Check this answer.

Related

Sub-class casting for methods

OK, so I'll start this with an example:
Let's say we have an abstract class with an interface variable, which is initialized in the constructor. The abstract class itself has a getter for that variable, it's subclasses have implementations of the interface in the constructor.
Now, the problem I'm getting is that when trying to call the getter of any of the subclasses (which is only declared in the superclass, but it should use the variable declared in their constructors) it doesn't return the implementation, it returns the interface itself.
public abstract class AbstractClass {
private final ExampleInterface exampleInterface;
public AbstractClass(ExampleInterface exampleInterface) {
this.exampleInterface = exampleInterface;
}
public ExampleInterface getExampleInterface() {
return this.exampleInterface;
}
}
public class AbstractClassSubclass extends AbstractClass {
//Instead of the interface itself, I provide my constructor it's implementation
public AbstractClassSubclass(ExampleInterfaceImplementation exampleInterfaceImpl) {
super(exampleInterfaceImpl);
}
}
public class TestClass {
private void testMethod() {
AbstractClassSubclass test = new AbstractClassSubclass(
new ExampleInterfaceImplementation()
);
//Would return ExampleInterface, instead of ExampleInterfaceImplementation
test.getExampleInterface();
}
}
Update
I believe I have fixed this using type parameters.
I'm sure I have tried it before but had a few problems...
Now it works perfectly.

What is the best practice in Java to set a constant required in subclasses?

I have the following situation:
A parent class has a function that depends on a constant. But the only valid place to define that constant is in subclasses (parent class cannot define the constant's value, but it can be used with the constant undefined in 99% of use cases - the constant is a default to use if a specific configuration element is missing).
However, I would like to enforce that any child class inheriting from that parent class must define the value for the constant, since any child classes have to be able to use the other 1% of functionality.
What is the best practice to implement this enforcement in Java, ideally at compile time? (clearly, at runtime, I can simply check if the constant is null/empty in the method using it).
My own solution was to implement a value-getter for the constant as an abstract method in the parent class, and call that in combination with the real setter in the constructor; something like this:
public class HelperClass1 {
private String myConstant;
public void setMyConstant() {} // implemented obviousy
public void myMethod() { // Called from ParentClass's methods
// Do something useful with myConstant
}
}
import HelperClass1;
public abstract class ParentClass {
ParentClass() {
HelperClass1.setMyConstant( getMyConstantValue() );
}
public abstract void getMyConstantValue();
}
public class ChildClass1 extends ParentClass {
public void getMyConstantValue() { return "BUZZ"; }
}
public class ChildClass2 extends ParentClass {
} // Fails to compile without getMyConstantValue()
However, (a) This implementation has a problem (I can't use ParentClass itself, since it's now abstract) without subclassing; and (b) since I'm not a Java developer, I'm afraid that this isn't the best or the most elegant solution. So I'd like to know if there's a best practices approach that improves on what I implemented.
Provide two constructors for the parent class:
One is a protected constructor which takes the constant as an argument.
The other is private constructor which can construct instances of the parent class without setting the constant.
Provide a factory method for the parent class which can call the private no-constant constructor.
Classes that want to get an instance of the parent class can call the factory method. But child classes that want to inherit from the parent class have to call the protected constructer, which can validate that a valid constant was passed.
public class ParentClass {
private final SomeClass myConstant;
protected ParentClass(SomeClass aConstant) {
if (null == aConstant) {
throw new IllegalArgumentException("...");
}
myConstant = aConstant;
}
private ParentClass() {
myConstant = null;
}
public static ParentClass getInstance() {
return new ParentClass();
}
}
public class ChildClass {
public ChildClass() {
super(new SomeClass(42));
}
}
This isn't perfect. Someone could write a child class that passes a bad constant to the superclass constructor, and it wouldn't actually fail until some code tried to construct an instance of the child class.

Test class for Abstract class with no default constructor and private method?

I have got a problem in my project and I'm putting up my problem in some sample example.
package com.sample.code;
public abstract class AbstractClass {
public String var1;
//in this class NO default constructor
public String method1(){
return "method1 "+privateMethod();
}
protected AbstractClass(String var1){
this.var1=var1;
}
private String privateMethod(){
return "private method";
}
}
I have got a private method that is used by my actual method and a protected single argumented constructor.
I need to write test case for my 'method1()'.
I need to use junit and EasyMock.
I would test it using concrete class implementation like:
MyConcreteClass clazz = ..;//MyConcreteClass could be local class or actual production class
Assert.assertEquals("method1 private method",clazz.method1());
Test class is also a typical java class, it can extend other classes, even tested class, so you can do this:
class AbstractClassTest extends AbstractClass
{
public AbstractClassTest()
{
super("some_string");
}
#Test
public void testMethod1()
{
//....
}
}
Since test class is extending base class you have to call in it's constructor the base class constructor. You don't have setter for this private field, so if you will need to test more instances you can instantiate test class inside test class:
AbstractClassTest abc = new AbstractClassTest("other_string");
To do this you will need second ctor for test class:
public AbstractClassTest(String param)
{
super(param);
}

How to instantiate a generic class

I thought I understood how to use .class and Class<> but I guess not. The below super(ApprovalWorkstation.class is not being mapped to the constructor. How can I be sure that I'm passing a class reference so that the base WorkstationRequest can instantiate it?
public class ApprovalWorkstation extends Workstation {
public ApprovalWorkstation(WorkstationEntity entity) {
super(entity);
}
}
public class WorkstationRequest extends com.production.socket.request.WorkstationRequest {
public WorkstationRequest() {
super(ApprovalWorkstation.class); //unable to map to constructor
}
}
This is the base WorkstationRequest that's extended above
public class WorkstationRequest {
private Class<Workstation> workstationClass;
public void WorkstationRequest(Class<Workstation> workstationClass) {
this.workstationClass = workstationClass;
}
update
I'm sorry for the confusion, my constructor actually has Class<Workstation> and not Workstation as I initially had.
In order to be able to pass both Workstation class and it's child classes you should change definition of WorkstationRequest to the following:
public class WorkstationRequest {
private Class<? extends Workstation> workstationClass;
public WorkstationRequest(Class<? extends Workstation> workstationClass) {
this.workstationClass = workstationClass;
}
}
Correct me if I am wrong, but you are passing in a Workstation instance while what needed is a Class<Workstation>. Maybe use workstationClass.getClass() instead?
You're trying to assign an instance of Worstation to field of type Class<Workstation> which is obviously not the same.
What you're probably trying to do is:
public WorkstationRequest(Class<Workstation> workstationClass) {
Of course there is no return type (void) in constructors. Your "constructor" is simply a method:
public void WorkstationRequest(Class<Workstation> workstationClass) { // method
public WorkstationRequest(Class<Workstation> workstationClass) { // constructor
There is no constructor that takes a Class as a parameter in the base WorkstationRequest class.
Constructors do NOT have a return type, so public void WorkstationRequest needs to be changed to public WorkstationRequest.

Instantiate an object from a dynamically generated class

I am currently trying to achieve something like this:
Based on this class, I try to create a new instance of the class Class<? extends AbstractValidator> returned by the method getValidator().
public abstract class AbstractEnumDefinition
extends AbstractRequestFieldDefinition {
private Vector<String> values = new Vector<String>();
public abstract void define(String lang);
protected void addEnumDefinition(String value){
values.add(value);
}
public Vector<String> getValues(){
return values;
}
#Override
public Class<? extends AbstractValidator> getValidator() {
return new AbstractValidator() {
#Override
public boolean isValid(String value) {
return values.contains(value);
}
#Override
public String getDefaultValue() {
return "";
}
}.getClass();
}
}
Say I create this class:
public class LanguageDefinition extends AbstractEnumDefinition {
public LanguageDefinition() {
super();
}
#Override
public void define(String language) {
addEnumDefinition("BEL-fr");
addEnumDefinition("BEL-nl");
addEnumDefinition("BEL-en");
}
}
Later in my code, I call
new LanguageDefinition().getValidator().getConstructor().newInstance()
The class I am trying to instantiate here is not declared anywhere, but "generated dynamically"/"dynamically created" within the AbstractEnumDefinition class.
When trying to do this, I get an java.lang.InstantiationException for
be....servlets.model.extraction.filter.editor.AbstractEnumDefinition$1
I guess this is due to the fact that this Class has to be explicitly created before hand, and not referenced dynamically?
Is there some kind of solution that would allow me to not have to write one class per validator?
Thanks for the help,
Eric
I can only make assumptions since i don't see the code where you are actually using the class, but you should check: http://docs.oracle.com/javase/6/docs/api/java/lang/InstantiationException.html
One thing it mentions is the instantiation can fail is the class is an abstract class (perfectly logical since you can't instantiate abstract classes).
Also, i don't see why you need to return the class and then create and object. Why not just define a Validator Interface and have your method return a Validator object.
That does not work for anonymous classes as far as I know, you have to convert your class to a named inner class:
But even that will not work, properly because you might not have a default constructor. Inner classes get implicit constructor arguments to keep the reference to the enclosing class. Unfortunately Closures do not work so well in static languages.
In summary inner classes that are non-static can not be instantiate outside of an instance of the enclosing class.

Categories

Resources