I have a class which calls two singleton classes FirstClass and SecondClass as below. Is there a way to access the data computed in FirstClass in the SecondClass. In this case I don't want to make external service call in second class since the first class has already called it. Instead, just use the data (stored in first class function) in the second data function. What are the ways to do it.
public class CallingFunction() {
List<String> generateData() {
return Lists.newArrayList(new FirstClass(), new SecondClass())
}
#Singleton
public class FirstClass() extends interface {
public String function() {
//operations. This function calls multiple services and stores ouput to hashMap
Map<String, String> hashedData = Maps.newHashMap();
hashedData.put(dataFromAnotherService);
return hashedData.get("abc");
}
}
#Singleton
public class SecondClass() extends interface {
public String function() {
//Use hashedData here instead of invoking the service again.
//Other operations
return "data";
}
}
Yes you can achieve the functionality by something below logic:
#Singleton
public class FirstClass() extends interface {
private static FirstClass instance;
private Map<String, String> hashedData = new HashMap<>();
public String function() {
//operations. This function calls multiple services and stores ouput to hashMap
hashedData.put(dataFromAnotherService);
return hashedData.get("abc");
}
public Map<String, String> getHashedData() {
return this.hashedData;
}
public static FirstClass getInstance() {
if (instance == null) instance = new FirstClass();
return instance;
}
}
#Singleton
public class SecondClass() extends interface {
public String function() {
FirstClass instance = FirstClass.getInstance();
// instance.getHashedData() here instead of invoking the service again.
//Other operations
return "data";
}
}
Related
I have following class/interface structure (can't modify the source):
public interface Car {}
public class CarA implements Car{
public String getASpecifics() {...}
}
public class CarB implements Car{
public String getBSpecifics() {...}
}
public class Summary {...}
I want to have a generic way of creating Summray for concrete implementations of Car interface which will be open to adding new implementations. My approach is following:
public CarSummarizer {
public interface SummaryGenerator<T extends Car> {
Summary generateSummary(T car);
}
static {
SummaryGenerator<CarA> aGen = c -> {... c.getASpecifics(); ...}
SummaryGenerator<CarB> bGen = c -> {... c.getBSpecifics(); ...}
}
}
Now I'd like to store aGen and bgen in a Map. I want to parametrize it so that I can offer one only public static method which accepts Car car and based on it's class object (car.getClass()) uses correct SummaryGenerator implemenation. That should look something like following:
public static Summary getSummaryForCar(Car car) {
return map.get(car.getClass()).generateSummary(car);
}
I don't know how to declare and instantiate that Map so that it's fully type-safe (i.e. doesn't allow inserting pair (CarC.class, SummaryGenerator<CarD>)). I'd like something like this:
public static <T extends Car> Map<Class<T>, SummaryGenerator<T>> map = new LinkedHashMap<>();
static {
// after instantiation
map.put(CarA.class, aGen);
map.put(CarB.class, BGen);
}
// also support following
public static <T extends Car> void addSummaryGenerator(T car, SummaryGenerator<T> sg) {
map.put(car.getClass(), sg);
}
That doesn't work because generics can't be declared on variables like they can be on functions.
I guess I could define new class public class SummarizerStorage<T extends Car> and the place map inside and just delegate calls. That seems like an overkill and ugly. I feel like it should be done somehow directly.
Declaring map like Map<Class<? extends Car>, SummaryGenerator<? extends Car>> would allow paring of Class<> and SummaryGenerator<> of sibling types. I want to allow only same type pairs.
You can do this with compile-time safety if you wrap your map and only allow to put entries of which the value SummaryGenerator<T> matches a key of Class<T>. To get the SummaryGenerator you need to cast but since you ensured that you only added entries that actually can be cast to SummaryGenerator<T>, this is safe to do. If you try to add an incompatible SummaryGenerator for a given implementation of Car, it would result in a compile error.
public class SummaryGeneratorStorage {
private static final Map<Class<? extends Car>, CarSummarizer.SummaryGenerator<? extends Car>> map = new HashMap<>();
// provides type safety to only add a SummaryGenerator<T> for a key of Class<T>
public static <T extends Car> void add(Class<T> clazz, CarSummarizer.SummaryGenerator<T> sg) {
map.put(clazz, sg);
}
#SuppressWarnings("unchecked")
public static <T extends Car> CarSummarizer.SummaryGenerator<T> get(T car) {
// this cast is safe since the add-method only
// allows a SummaryGenerator<T> to be added for a key of Class<T>
return (CarSummarizer.SummaryGenerator<T>) map.get(car.getClass());
}
private SummaryGeneratorStorage() { }
}
In order to get a Summary, you retrieve the registered SummaryGenerator for the Car and call the implemented generateSummary method. If no SummaryGenerator is found for the passed implementation of Car, just throw an exception or handle it a different way. Note that the signature of add takes a Class and not a Car object since we don't need an instance at this point to make the reference to an implementation of Car.
public class CarSummarizer {
public interface SummaryGenerator<T extends Car> {
Summary generateSummary(T car);
}
static {
// here you cannot pass incompatible implementations of Car (compile-time safety)
SummaryGenerator<CarA> aGen = c -> new Summary(c.getASpecifics());
SummaryGeneratorStorage.add(CarA.class, aGen); // with variable
SummaryGeneratorStorage.add(CarB.class, c -> new Summary(c.getBSpecifics())); // direct
}
public static <T extends Car> Summary getSummary(T car) {
SummaryGenerator<T> generator = SummaryGeneratorStorage.get(car);
if (generator != null) {
return generator.generateSummary(car);
} else {
throw new IllegalArgumentException("no summary generator found");
}
}
}
Here is a test class for the above code. A simple Summary containing a name-field was used and the implementations of Car return A, B or C in their getXSpecifics() methods:
public class CarSummarizerTest {
#Test
public void testCarA() {
CarA car = new CarA();
Summary summary = CarSummarizer.getSummary(car);
Assert.assertEquals(car.getASpecifics(), summary.getName());
}
#Test
public void testCarB() {
CarB car = new CarB();
Summary summary = CarSummarizer.getSummary(car);
Assert.assertEquals(car.getBSpecifics(), summary.getName());
}
#Test
public void testCarC() {
CarC car = new CarC();
Assert.assertThrows(IllegalArgumentException.class, () -> {
CarSummarizer.getSummary(car);
});
}
}
For completeness the other classes:
public class CarA implements Car {
public String getASpecifics() { return "A"; }
}
public class CarB implements Car {
public String getBSpecifics() { return "B"; }
}
public class CarC implements Car {
public String getCSpecifics() { return "C"; }
}
public class Summary {
private final String name;
public Summary(String name) { this.name = name; }
public String getName() { return name; }
}
I am trying to write some generic code and facing issue. Here is code
public abstract class AbstractService<D extends IDTO> {
public String ex(D dto) {
return null;
}
}
public class AService extends AbstractService<TestA> {
#Override
public String ex(TestA dto) {
return "a";
}
}
public class BService extends AbstractService<TestB> {
#Override
public String ex(TestB dto) {
return "b";
}
}
class TestA impements IDTO {
}
class TestB impements IDTO {
}
So as you can see, its really simple code, one AbstractService with bounded param that extends IDTO.
Two implementation of service AService and BService which uses their respective DTO.
Not there is another class that need to call ex() method on basis of runtime instance.
here I am facing the problem.
public class TestAll {
public void executeRequest(final IDTO dto){
// serviceMap contains list of all Services here A and B
serviceMap.get(type).ex(dto);
}
}
Problem on line build().
The method build(capture#5-of ? extends IDTO) in the type AbstractService is not applicable for the arguments (IDTO)
Could someone help to fix this issue?
I found the reason why it was giving me the error. It was my mistake as I was trying to build a map with the help of Spring and was using bounded approach.
It was my previous code.
#Autowired
public void setServicesList(List<AbstractService<IDTO>> abstractServices) {
serviceMap = abstractServices.stream().collect(Collectors.toMap(AbstractService::getType, Function.identity()));
}
and I had to remove the bounded approach and now it's working.
public void setServicesList(List<AbstractService> abstractServices) {
serviceMap = abstractServices.stream().collect(Collectors.toMap(AbstractService::getType, Function.identity()));
}
In case you know what type of service holds the Map, you could do following:
// define your service map
private final Map<String, AbstractService<? extends IDTO>> serviceMap = Map.of(
"a", new AService(),
"b", new BService());
// cast `AbstractServise` from the map into required type:
public void executeRequest(final TestA dto){
((AbstractService<TestA>)serviceMap.get("a")).ex(dto);
}
public void executeRequest(final TestB dto){
((AbstractService<TestB>)serviceMap.get("b")).ex(dto);
}
I have a lot of actions. All actions works with some Object/Context that passed in all actions. I want to use pattern Strategy/Policy.
Here is examples in Kotlin:
interface Action {
val name: String
fun run(ctx: Context)
}
class Multiply: Action {
override name = "MULTIPLY"
override fun run(ctx: Context) {
writeToDb(ctx.id, ctx.number * 2)
}
}
class Substract
class SendNotification
etc...
So I want to register all strategies on startup. And select strategy from structure like Enum.
val action = selectAwaitingAction()
val ctx = selectCtxById(action.transaction_id)
perfromAction(ctx, actions.getByName(action.name))
fun performAction(ctx Context, action: Action) {
action.run(ctx)
}
My question is how register strategy by interface type?
Note: This is complete example. If you are looking only for automatic registration by interface type, scroll to last part of answer.
Strategy design pattern can be implemented using function tables. This stores implementations in Map<String,IImpl> where key is name of algorithm and value is concrete implementation of algorithm .
Common approach:
Consider class Context holding all parameters shared between imlementations of interface Solver.
public class Context extends HashMap<String,Object> {
public <T> T get(String key, Class<T> resultClass){
return resultClass.cast(get(key));
}
public <T> T getOrDefault(String key, T def, Class<T> resultClass){
return resultClass.cast(getOrDefault(key,def));
}
}
And interface Solver with required methods solve and name
public interface Solver {
void solve(Context context);
String name();
}
Then you can create implementations of Solver interface modifying shared Context object. I have created AddSolver and MultiplySolver in this example.
AddSolver.java:
public class AddSolver implements Solver {
#Override
public void solve(Context context) {
context.put("result", context.getOrDefault("result",0.0, Double.class) + context.get("add", Double.class));
}
#Override
public String name() {
return "+";
}
}
MultiplySolver.java
public class MultiplySolver implements Solver {
#Override
public void solve(Context context) {
context.put("result", context.getOrDefault("result",0.0, Double.class) * context.get("multiply", Double.class));
}
#Override
public String name() {
return "*";
}
}
Manual construction of Map<String,Solver>:
Implementations of interface Solver can be stored in HashMap<String,Solver>
#Test
public void testCustomFunctionMap(){
HashMap<String,Solver> functionMap = new HashMap<>();
functionMap.put("+", new AddSolver());
functionMap.put("*", new MultiplySolver());
Context context = new Context();
context.put("add", 2.0);
functionMap.get("+").solve(context);
TestCase.assertEquals(2.0, context.get("result", Double.class));
context.put("multiply", 3.0);
functionMap.get("*").solve(context);
TestCase.assertEquals(6.0, context.get("result", Double.class));
}
Automatic construction of Map<String,Solver>
There is more approaches, if you need costruct Map<String,Solver> automatically. A lot of them is mentioned in this question. I have used org.reflections library.
public class SolverScanner{
static HashMap<String, Solver> functionMap;
static {
functionMap = new HashMap<>();
Reflections reflections = new Reflections(SolverScanner.class.getPackage().getName());
for( Class<? extends Solver> clazz : reflections.getSubTypesOf(Solver.class)){
try {
Solver solver = clazz.newInstance();
functionMap.put(solver.name(), solver);
} catch (Exception e) {
throw new IllegalStateException("Cannot construct functionMap",e);
}
}
}
public static HashMap<String, Solver> getFunctionMap(){
return functionMap;
}
private SolverScanner(){}//disable instantiating
}
And usage:
#Test
public void testSolverScannerFunctionMap(){
HashMap<String,Solver> functionMap = SolverScanner.getFunctionMap();
Context context = new Context();
context.put("add", 2.0);
functionMap.get("+").solve(context);
TestCase.assertEquals(2.0, context.get("result", Double.class));
context.put("multiply", 3.0);
functionMap.get("*").solve(context);
TestCase.assertEquals(6.0, context.get("result", Double.class));
}
I have written simple container that registers a class and it's interface and has a method to create object from that information like this:
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) throws Exception{
if(!this.classMap.containsKey(interf))
throw new Exception("No such class registered with "+interf.getName()+" interface");
return this.classMap.get(interf).newInstance();
}
}
But I want before creating new instance to bypass it to proxy, for it to create, so I have this proxy class:
public class MyProxy implements InvocationHandler
{
private Map map;
private Object obj;
public static Object newInstance(Map map, Object obj, Class[] interfaces)
{
return Proxy.newProxyInstance(map.getClass().getClassLoader(),
interfaces,
new MyProxy(map, obj));
}
public MyProxy(Map map, Object obj)
{
this.map = map;
this.obj = obj;
}
public Object invoke(Object proxy, Method m, Object[] args) throws
Throwable
{
try {
return m.invoke(obj, args);
} catch (NoSuchMethodError e)
{
//Object result;
String methodName = m.getName();
if (methodName.startsWith("get"))
{
String name = methodName.substring(methodName.indexOf("get")+3);
return map.get(name);
}
else if (methodName.startsWith("set"))
{
String name = methodName.substring(methodName.indexOf("set")+3);
map.put(name, args[0]);
return null;
}
else if (methodName.startsWith("is"))
{
String name = methodName.substring(methodName.indexOf("is")+2);
return(map.get(name));
}
return null;
}
}
}
But for proxy class I need to provide type of class and it's interface, but I only have it's information with X.class. Can get the type (for example if it's class X) X, when I have X.class? Maybe I'm doing this the wrong way and I need to change something in order for it to work, but right now I figured I need to get that class type, so then I could provide it for proxy?
Because if I would right something like this:
X.class x;
I would get error. So I need to write like this X x;, but I only have X.class
Update:
To explain it simply, is it possible to get this:
X obj;
when you only have X.class (with X.class.newInstance it would instantiate it (like with new?), but I need not instantiated obj yet).
Update2
I tried this:
Object x = (Object) MyProxy.newInstance(map, this.classMap.get(interf).newInstance(), new Class[] {this.classMap.get(interf)});
But then I get this error:
Exception in thread "main" java.lang.IllegalArgumentException: class lab.X is not visible from class loader
My class X looks like this:
public class X implements I{
String name;
X(){}
#Override
public String getName() {
return name;
}
#Override
public void setName(String name) {
this.name = name;
}
}
and it's interface looks like this:
public interface I {
public String getName();
public void setName(String name);
}
If I understand correctly, you are trying to instantiate an element of the class X.class? If that is the case, all you need to do is call X.class.newInstance().
java.lang.IllegalArgumentException: class lab.X is not visible from
class loader
Isn't this error message quite clear? You need to make sure that the same class loader is being used.
In here:
public static Object newInstance(Map map, Object obj, Class[] interfaces)
{
return Proxy.newProxyInstance(map.getClass().getClassLoader(),
interfaces,
new MyProxy(map, obj));
}
you shouldn't be using the class loader of the map, I'd think you should use class loader of the target object or pass the proper class loader as a separate argument.
I think there are other problems in your approach as well, such as not synchronizing your container creation and not using generics for your proxy type.
For the first part, class DIContainer, it would be better to use:
protected final Map<Class<?>, Class<?>> classMap;
protected DIContainer() {
classMap = Collections.synchronizedMap(new HashMap<Class<?>, Class<?>>());
}
public <I> void regClass(Class<I> interf, Class<? extends I> classToReg) {
this.classMap.put(interf, classToReg);
}
public <T> T create(Class<T> interf) throws Exception {
Class<?> implClass = classMap.get(interf);
if (implClass == null) {
throw new Exception("No such class registered with " + interf.getName()
+ " interface");
}
Constructor<?> c = implClass.getConstructor();
c.setAccessible(true); // If default constructor not public
return interf.cast(c.newInstance());
}
Safe typing, though still partly at run-time.
More or less obsolete Hashtable replaced by equivalent
Calling newInstance on the class bypasses exceptions thrown on getting the default constructor and doing that one's newInstance.
The second part of the question: I fail to understand it; the interface class(es) is what is proxied. In the create above you could easily proxy Class<T> and yield a (seemingly) T object. And you could delegate in the proxy class to an T object created as in the create above.
I have a class for example
public class Example<T> {...}
I would like to instantiate class Example with a specific type class which I know. Pseudocode would look something like that
public Example<T> createTypedExample(Class exampleClass, Class typeClass) {
exampleClass.newInstance(typeClass); // made-up
}
So that this would give me same result
Example<String> ex = new Example<String>();
ex = createTypedExample(Example.class, String.class);
Is it possible in Java?
Since, the return type i.e. the class of the new instance is fixed; there's no need to pass it to the method. Instead, add a static factory method to your Example class as
public class Example<T> {
private T data;
static <T> Example<T> newTypedExample(Class<T> type) {
return new Example<T>();
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
Now, here's how you would create generic Example instances.
// String
Example<String> strTypedExample = Example.newTypedExample(String.class);
strTypedExample.setData("String Data");
System.out.println(strTypedExample.getData()); // String Data
// Integer
Example<Integer> intTypedExample = Example.newTypedExample(Integer.class);
intTypedExample.setData(123);
System.out.println(intTypedExample.getData()); // 123