How to set bean class at runtime

325 views Asked by At

Example: I have a an abstract class "animal" and subclass "lion" and "tiger". Subclass name is written on NotesDocument field "Form". How do i create bean named animal with class "Tiger" or "Lion" at runtime.

My plan is: I make a bean with managed-bean-name "animal", managed-bean-class "AnimalFactory". Then somewhere, where?, I want to (pseudocode)

Document doc = database.getDocById("AAAA"); //from docId parameter
String animalType = doc.getItemValueString("Form");
if (animalType.equals("Lion") return makeLionInstance();
else return makeTigerInstance();

Can someone point me in a right direction or give me an example?

EDIT

I havent study any answers provided... Will do tomorrow.

Problem is we have 100k-300k LoC project and noone knows what exactly it is doing. It is 15 years old and had 30-50 developers. Anyway, we decided to go web. In java we see a great oppurtunity to rewrite project to java (as many have already done), remove redundant code, define interfaces etc (and later, where no MS objects are involved, replace java code with LS code)... We have 6 different (with similar base) doc (form)types with subtypes and every type has 5 different workflows, which are exclusive.

I dont have the knowledge of how to instantiate specific class from notesdocument at runtime. One workaround is to provide variables to base class and instantiate them at runtime based on field "Form". I have a feeling, this will not suffice in the long run.

As in my "plan", I THINK I have a vague idea of what must be done. I dont know where to insert code, neither what I must be careful about.

TL:DR

How to have instance of type defined on document field "Form" resolved to managed bean at runtime.

4

There are 4 answers

1
Frantisek Kossuth On

I think this article was revolutionary at the time. It helped me a lot to take control over managed beans. Get inspired by it and make factory bean Zoo implementing Map interface. Your get(String) method will instantiate or retrieve according animal object based on its name.

Your EL/SSJS will be easy as:

#{zoo.lion}
#{javascript:zoo.get("Lion").roar()}
0
KDP On

Factory pattern will be suffice and enhancement to this will be like initialize a map with key as the animal subclass name and value as actual instance.

animalMap.put("Lion", LionObject);
animalMap.put("Tiger", TigerObject);

from the form get the key and return the instance. for example if the value from form is Tiger then you can get the instance like

animalMap.get("value passed from the map") --> animalMap.get("Tiger").
0
Daniel On

There are a lot of solutions to the particular problem, and they depend on where you're going to go with it.

I would start by creating an interface AnimalFactory.

interface AnimalFactory<T extends Animal> {
    T create();
}

Then, I would create a mapping:

private final Map<String, AnimalFactory<?>> factories = initFactories();

private Map<String, AnimalFactory<?>> initFactories() {
   final Map<String, AnimalFactory<?>> factories = new HashMap<>();
   // Note, in Java 8, you can simplify these anonymous classes to "Tiger::new" and "Lion::new".
   factories.put("lion", new AnimalFactory<Lion>() {
        public void create() { return new Lion(); }
   }); 
   factories.put("tiger", new AnimalFactory<Tiger>() {
        public void create() { return new Tiger(); }
   }); 
   return map;
}

public Animal createAnimal(String type) {
   final AnimalFactory<?> factory = factories.get(type.toLowercase());
   if (factory == null) { return null; }
   return factory.create();
}
0
TheCodingFrog On

You can use enums as a factory pattern and they are singleton also.

package com.test;

public enum AnimalFarm {

    LION(new Lion()),
    TIGER(new Tiger());

    private Animal animal;
    private AnimalFarm(Animal animal) {
        this.animal = animal;
    }

    private static Animal getAnimalByName(String name) {
        return AnimalFarm.valueOf(name.toUpperCase()).animal;
    }
}