Getting rid of if/else while calling similar classes Java - java

I have the problem that I want to and need to get rid of some if else cases. I got the following code in my project:
if (ar[4].equals("week")) {
WeekThreshold wt = new WeekThreshold();
firstTime = unparsedDate.format(wt.getStartDate().getTime());
secondTime = unparsedDate.format(wt.getEndDate().getTime());
} else if (ar[4].equals("month")) {
MonthThreshold mt = new MonthThreshold();
firstTime = unparsedDate.format(mt.getStartDate().getTime());
secondTime = unparsedDate.format(mt.getEndDate().getTime());
} else if (ar[4].equals("quarter")) {
quarterThreshold();
} else if (ar[4].equals("year")) {
YearThreshold yt = new YearThreshold();
firstTime = unparsedDate.format(yt.getStartDate().getTime());
secondTime = unparsedDate.format(yt.getEndDate().getTime());
}
That three classes WeekThreshold, MonthThreshold and YearThreshold extend from an AbstractThreshold class where they get dates from a calendar, but that is not important. The method quarterThreshold() is special and can stay there. But how can I get rid of that if else blocks and have one statement to call different classes?
EDIT: Forgot to mention, the classes that need to be called are from a variety of the array ar[]. If the array ar[4] is month, MonthThreshold must be called, etc.

Multiple possibilities... Do the XYZThreshold classes have a common interface, like Threshold? Then you could assign a variable with that, for example...
Threshold threshold = null;
if ((ar[4].equals("week")) {
threshold = new WeekThreshold();
} else ... {
}
firstTime = unparsedDate.format(threshold.getStartDate().getTime());
secondTime = unparsedDate.format(threshold.getEndDate().getTime());
That would be a first step. If you wanted, you could, for example, use an enum to store your Thresholds:
enum Thresholds {
WEEK("week") {
public Threshold getThreshold() {
return new WeekThreshold();
}
},
etc.
private String period;
private Thresholds(String period) {
this.period = period;
}
public abstract Threshold getThreshold();
// ...add a static class to iterate and search by period,
// ...so you can write Threshold threshold = Thresholds.getByPeriod("week").getThreshold();
}
Using enums is a personal taste, of course, you can do the same thing with normal classes or by simply putting your if-block for the Threshold-choosing into a seperate class.

You can merge the common code (unparsedDate.format(...)) outside like this:
AbstractThreshold at = null;
switch(ar[4]) {
case "week":
at = new WeekThreshold();
break;
case "month":
at = new MonthThreshold();
break;
case "year":
at = new YearThreshold();
break;
case "quarter":
quarterThreshold();
break;
}
if(at != null) {
firstTime = unparsedDate.format(at.getStartDate().getTime());
secondTime = unparsedDate.format(at.getEndDate().getTime());
}
Of course an overengineered version is possible. Here's just an illustration how it can be implemented using the Java-8 features:
// Map can be initialized only once, then used many times
Map<String, Supplier<AbstractThreshold>> thresholdSuppliers = new HashMap<>();
thresholdSuppliers.put("week", WeekThreshold::new);
thresholdSuppliers.put("month", MonthThreshold::new);
thresholdSuppliers.put("year", YearThreshold::new);
AbstractThreshold at = thresholdSuppliers.getOrDefault(ar[4], () -> null).get();
if(at != null) {
firstTime = unparsedDate.format(at.getStartDate().getTime());
secondTime = unparsedDate.format(at.getEndDate().getTime());
} else if(ar[4].equals("quarter"))
quarterThreshold();
}

Here you can make good use of the FactoryPattern
class ThresholdFactory
{
public static AbstractThreshold getThreshold(String criteria)
{
if ( criteria.equals("week") )
return new WeekThreshold();
if ( criteria.equals("month") )
return new MonthThreshold();
if ( criteria.equals("year") )
return new YearThreshold();
return null;
}
}
The rest of the code looks then like this:
AbstractThreshold at = ThresholdFactory.getThreshold(ar[4]);
if(at != null){
firstTime = unparsedDate.format(at.getStartDate().getTime());
secondTime = unparsedDate.format(at.getEndDate().getTime());
} else {
quarterThreshold();
}

first create threshold factory,
static enum ThresholdsFactory {
week(new WeekThreshold()), month(new MonthThreshold())/* etc */;
static private Map<String,ThresholdsFactory> lookup = new HashMap<String, ThresholdsFactory>();
static{
for(ThresholdsFactory val : ThresholdsFactory.values()){
lookup.put(val.name(), val);
}
}
public AbstractThreshold threshold;
public static ThresholdsFactory find(String name){
return lookup.get(name);
}
ThresholdsFactory(AbstractThreshold th) {
threshold = th;
}
}
now all what you need to do is
AbstractThreshold th = ThresholdsFactory.find(ar[4]);
if (th!=null){
firstTime = unparsedDate.format(th.getStartDate().getTime());
secondTime = unparsedDate.format(th.getEndDate().getTime());
}

Here is an example of how to use interfaces and Factory design pattern
If your multiple implementors share common code, have them all extend an Abstract class that implements the interface. It is a good idea to refer to your methods through the interface, not the concrete class to take advantage of polymorphism ... see code below ...
public class Example {
public static void main(String[] args) {
String[] intervals = {"week", "week", "quarter", "month", "year", "week"};
IThreshold[] objects = new IThreshold[intervals.length];
// Create your objects using Factory pattern
for(int index = 0; index < intervals.length; index++) {
objects[index] = ThresholdFactory.createInstance(intervals[index]);
}
// Now iterate through your objects and refer to them through a common interface
for(IThreshold object : objects) {
int start = object.getFirstTime();
int end = object.getFirstTime();
}
}
}
interface IThreshold {
public int getFirstTime();
public int getLastTime();
}
abstract class AbstractThreshold implements IThreshold {
#Override
public int getFirstTime() {
// TODO Auto-generated method stub
return 0;
}
#Override
public int getLastTime() {
// TODO Auto-generated method stub
return 0;
}
}
class WeekThreshold extends AbstractThreshold {}
class MonthThreshold extends AbstractThreshold {}
class QuarterThreshold extends AbstractThreshold {}
class YearThreshold extends AbstractThreshold {}
class ThresholdFactory {
public static final IThreshold createInstance(String interval) {
IThreshold instance = null;
if(interval.equals("week")){
instance = new WeekThreshold();
}
else if(interval.equals("month")){
instance = new MonthThreshold();
}
else if(interval.equals("quarter")){
instance = new QuarterThreshold();
}
else {
if(interval.equals("year")){
instance = new YearThreshold();
}
}
return instance;
}
}

You could use a switch statement
String typeOfDay;
switch (dayOfWeekArg) {
case "Monday":
typeOfDay = "Start of work week";
break;
case "Tuesday":
case "Wednesday":
case "Thursday":
typeOfDay = "Midweek";
break;
case "Friday":
typeOfDay = "End of work week";
break;
case "Saturday":
case "Sunday":
typeOfDay = "Weekend";
break;
default:
throw new IllegalArgumentException("Invalid day of the week: " + dayOfWeekArg);
}
You can replace the example that I stole from java documentation, with your own code
switch(periodType){
case "week":
WeekThreshold wt = new WeekThreshold();
break; // add your other cases
}
firstTime = unparsedDate.format(wt.getStartDate().getTime());
secondTime = unparsedDate.format(wt.getEndDate().getTime());

Related

How to replace switch-case to OOP

I have methods with which I get data from a database.
Depending on the variable that the user entered through the console, I must execute the desired method
while (flag) {
try {
sw = new ScannerWrapper();
menuHeader();
int choice = sw.readInt();
switch (choice) {
case 1:
System.out.println("Input first name: ");
String name = sw.readLine().toUpperCase();
printResults(DataParser.getFilmByName(name));
break;
case 0:
System.out.println("Bye-bye. Come again");
flag = false;
break;
default:
System.out.println("Please enter correct number");
}
} catch (Exception e) {
System.out.println("Enter correct data");
} finally {
DBConnector.getInstance().closeConnection();
}
}
This code is very bad.There are more than 5 cases with methods and the code becomes redundant
You should have a look at the Strategy design pattern. That will allow you to abstract the logic related to an action.
On top of that, you want to replace the switch to find the right strategy according to the input variable. That is the job of the Factory design pattern, which in your case would return one of the different strategies according to the database value.
Basically:
interface UserAction {
public void execute();
}
class ListMovies implements UserAction {
public void execute() {
// List the movies
}
}
class ExitProgram implements UserAction {
public void execute() {
// Kill kenny
}
}
class Noop implements UserAction {
public void execute() {
// Do nothing
}
}
And a factory:
class UserActionFactory {
public UserAction make(int actionId) {
switch (actionId) {
0: return new ListMovies();
1: return new ExitProgram();
default: return new Noop();
}
}
}
Which then allows:
UserActionFactory factory = new UserActionFactory();
ScannerWrapper sw = new ScannerWrapper();
while (true) {
menuHeader();
int choice = sw.readInt();
UserAction action = factory.make(choice);
action.execute();
}
This could also be the Command design pattern, depends on how you name things and instantiate objects for the rest of the classes.

How to inject a method invocation into another method in android

I have a class with,
a field called something,
a setter method called setSomething, and,
a method called onChange which should be called every time something is changed.
I want to be able to freely add more fields and have the same behavior for all of them.
I don't want to manually call onChange because,
A lot of boilerplate,
Code will be written in Kotlin so I don't want to write setter functions at all.
The ideal solution I've been able to think of has been to somehow inject the onChange call right before the return for each setter method in compile time.
I've looked at annotation processing, but apparently classes aren't actually compiled at that stage, so I'd have to generate the entire class all over again? I don't exactly understand this.
The other option seems to be writing a gradle plugin that will find the relevant class(es) and modify their bytecode.
I've actually started work on this as a pure Java project (gradle plugin is semi-done) and have been able to find the classes and inject the method call. Can't seem to successfully write the results to a class file though.
Here's what I have (using BCEL):
public class StateStoreInjector {
public static void main(String[] args) {
// Find all classes that extends StateStore
Reflections reflections = new Reflections("tr.xip.statestore");
Set<Class<? extends StateStore>> classes = reflections.getSubTypesOf(StateStore.class);
for (Class c : classes) {
try {
JavaClass clazz = Repository.lookupClass(c.getName());
JavaClass superClazz = Repository.lookupClass(StateStore.class.getName());
if (Repository.instanceOf(clazz, superClazz)) {
injectInClass(clazz, superClazz);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
private static void injectInClass(JavaClass clazz, JavaClass superClazz) {
ClassGen classGen = new ClassGen(clazz);
ConstantPoolGen cp = classGen.getConstantPool();
// Find the onChange method
Method onChangeMethod = null;
for (Method m : superClazz.getMethods()) {
if (m.getName().equals("onChange")) {
onChangeMethod = m;
}
}
if (onChangeMethod == null) {
throw new RuntimeException("onChange method not found");
}
ClassGen superClassGen = new ClassGen(superClazz);
ConstantPoolGen superCp = superClassGen.getConstantPool();
// Add onChange method ref to the class ConstantPool
MethodGen onChangeMethodGen = new MethodGen(onChangeMethod, superClassGen.getClassName(), superCp);
cp.addMethodref(onChangeMethodGen);
// Loop through all methods to inject method invocations if applicable
for (Method m : clazz.getMethods()) {
// Skip methods with names shorter than 3 chars - we're looking for setters and setters would be min 4 chars
if (m.getName().length() < 3) continue;
// Check if the method actually starts with the keyword "set"
boolean isSetMethod = m.getName().substring(0, 3).toUpperCase().equals("SET");
// Get method name without the "set" keyword
String methodName = m.getName().substring(3, m.getName().length());
// Check that we actually have a field set by this setter - that this setter is "valid"
boolean fieldWithSameNameExists = false;
for (Field f : clazz.getFields()) {
if (f.getName().toUpperCase().equals(methodName.toUpperCase())) {
fieldWithSameNameExists = true;
break;
}
}
// Proceed with injection if criteria match
Method newMethod = null;
if (isSetMethod && fieldWithSameNameExists) {
newMethod = injectInMethod(m, onChangeMethodGen, classGen, cp);
}
// Injection returned. Do we have a new/modified method? Yes? Update and write class.
if (newMethod != null) {
classGen.removeMethod(m);
classGen.addMethod(newMethod);
classGen.update();
try {
String packageName = clazz.getPackageName().replace(".", "/");
String className = clazz.getClassName();
className = className.substring(className.lastIndexOf(".") + 1, className.length());
clazz.dump(packageName + "/" + className + "Edited.class");
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static Method injectInMethod(Method m, MethodGen onChangeMethodGen, ClassGen cg, ConstantPoolGen cp) {
MethodGen methodGen = new MethodGen(m, cg.getClassName(), cp);
InstructionList il = methodGen.getInstructionList();
println(il.toString() + "pre insert ^");
// Find the "return" instruction
Instruction returnInstruction = null;
for (Instruction i : il.getInstructions()) {
if (i.getOpcode() == 177) returnInstruction = i;
}
// If found, insert onChange invocation instruction before the return instruction
if (returnInstruction != null) {
int index = cp.lookupMethodref(onChangeMethodGen); // Find the index of the onChange method in the CP
il.insert(returnInstruction, new INVOKEVIRTUAL(index)); // Insert the new instruction
println(il.toString() + "post insert ^");
il.setPositions(); // Fix positions
println(il.toString() + "post set pos ^");
il.update();
methodGen.update();
return methodGen.getMethod();
}
return null;
}
private static void println(String message) {
System.out.println(message);
}
}
Input Java class:
public class DummyStateStore extends StateStore {
private int id = 4321;
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
}
Parent Store class:
public class StateStore {
public void onChange() {
// notifies all subscribers
}
}
Output (decompiled) class file:
public class DummyStateStore extends StateStore {
private int id = 4321;
public DummyStateStore() {
}
public void setId(int id) {
this.id = id;
}
public int getId() {
return this.id;
}
}
Log output:
0: aload_0[42](1)
1: iload_1[27](1)
2: putfield[181](3) 2
5: return[177](1)
pre insert ^
0: aload_0[42](1)
1: iload_1[27](1)
2: putfield[181](3) 2
-1: invokevirtual[182](3) 26
5: return[177](1)
post insert ^
0: aload_0[42](1)
1: iload_1[27](1)
2: putfield[181](3) 2
5: invokevirtual[182](3) 26
8: return[177](1)
post set pos ^
(I checked the index 26 by debugging the code and it is the correct index in the CP)
Now, the questions are:
Why can't the invocation be seen in the decompiled code but it seems to be added to the instructions list? What am I missing?
Where would I be exporting the modified class files in an android build for them to be included in the final apk?
You're trying to use reflection, but there should be no need to do so with Kotlin as you can create higher order functions (functions that take functions as inputs).
You could do something like:
class ChangeableType<T>(private var value: T, private val onChange: () -> Unit) {
fun set(value: T) {
this.value = value
this.onChange.invoke()
}
}
class MyRandomClass() {
val something = ChangeableType(0, { System.print("Something new value: $value") })
val anotherThing = ChangeableType("String", { System.print("Another thing new value: $value") })
}
class ConsumingClass {
val myRandomClass = MyRandomClass()
fun update() {
myRandomClass.apply {
something.set(1)
anotherThing.set("Hello World")
}
}
}

Get null value from another object in Java, but get value in own class

When I try to execute this code, after I choose AMD, I got null in value. how it can be happen ?
below is the source code :
[for main]
public class processor{
public int hargapro;
public String nmbarangpro;
public static final Scanner input = new Scanner(System.in);
public String getpro()
{
return nmbarangpro;
}
public int getproharga()
{
return hargapro;
}
public void daftarpro() {
List<String> daftarpro = new ArrayList<>();
daftarpro.add("AMD");
daftarpro.add("Intel");
List<String> nomer = new ArrayList<>();
nomer.add("1. ");
nomer.add("2. ");
System.out.println("Processor yang tersedia :");
for (int i = 0; i < daftarpro.size(); i++) {
System.out.println(nomer.get(i)+daftarpro.get(i));
}
System.out.println("Pilihan anda : ");
int pilih = input.nextInt();
switch(pilih)
{
case 1:
{
System.out.println("Anda membeli Processor AMD");
System.out.println("Seharga Rp 1.200.000");
harga(1200000); //call harga method
namabarang("AMD"); //call namabarang method
System.out.println(getpro()); //[for testing]filled with AMD[ni problem here]
System.out.println(getproharga()); //[for testing][filled with 1200000[no problem here]
break;
}
case 2:
{
System.out.println("Anda membeli Processor AMD");
System.out.println("Seharga Rp 1.200.000");
harga(1500000);
namabarang("Intel");
break;
}
default:
System.out.println("Pilihan tidak tersedia");
daftarpro();
}
}
#Override
public int harga(int hargamasuk) {
return hargapro = hargamasuk;
}
#Override
public String namabarang(String barang) {
return nmbarangpro = barang;
}
public static void main(String[] args) {
processor a = new processor();
a.daftarpro();//get menu from daftarpro()
kasir x = new kasir();
x.semua();//get null in value
}
}
my second files :
public class kasir {
public void semua()
{
processor a = new processor();
System.out.println(a.getpro());
}}
When I try to read value through class kasir, i get x.semua filled with null value. how it can be happen ?
Your semua method creates a new instance of processor which it then reads from:
public void semua()
{
processor a = new processor();
System.out.println(a.getpro());
}
That's entirely unrelated to the processor instance you've created in your main method. If your kasir class should logically "know about" the other processor instance, you probably want a processor field in the class, which you might populate via the constructor - so your main method might become:
public static void main(String[] args) {
processor a = new processor();
a.daftarpro();
kasir x = new kasir(a);
x.semua();
}
As an aside, you should really try to follow the Java naming conventions, so classes of Processor and Kasir, and methods of getPro etc. (And if your code actually looks like that in your editor, I suggest you reformat it, too...)

How to simplify multiple if else with simple for loop?

I have to check each and every condition with this repetitive if else loop. How to simplify with for loop or any other method?
if(color.equals("1")&&id.equals("pant"))
{
}
else if(color.equals("2")&&id.equals("pant"))
{
}
else if(color.equals("3")&&id.equals("pant"))
{
}
else if(color.equals("4")&&id.equals("pant"))
{
}
else if(color.equals("5")&&id.equals("pant"))
{
}
else if(color.equals("6")&&id.equals("pant"))
{
}
if(color.equals("1")&&id.equals("shirt"))
{
}
else if(color.equals("2")&&id.equals("shirt"))
{
}
else if(color.equals("3")&&id.equals("shirt"))
{
}
else if(color.equals("4")&&id.equals("shirt"))
{
}
else if(color.equals("5")&&id.equals("shirt"))
{
}
else if(color.equals("6")&&id.equals("shirt"))
{
}
You can use two for loops for this purpose,
first get a list which contains two elements that is "shirts" and "pants" something like
string [2] cloths = {"pants","shirts"};
and a variable like i and set that to 1 first
int i = 1;
and then
for (string cloth : cloths)
{
for (i = 1; i < 7 ; i++)
{
if(color.equals(i.toString())&&id.equals(cloth))
{
System.out.println(i.toString()+"&"+cloth);
}
}
}
The whole idea is like this but There maybe some minor syntax errors since I didn't compile the code
switch (Integer.parseInt(color))
{
case 1:
if (id == "pant")
{
// 1:pant
}
else if (id == "shirt")
{
// 1:shirt
}
break;
case 2:
if (id == "pant")
{
// 2:pant
}
else if (id == "shirt")
{
// 2:shirt
}
break;
// etc ...
}
You can use inner if statements to achieve a slightly simpler.
if (id.equals("pant")) {
if (color.equals("1")) {
//code
}
else if (color.equals("2")) {
//code
}
//etc
}
else if (id.equals("shirt")) {
if (color.equals("1")) {
//code
}
else if (color.equals("2")) {
//code
}
//etc
}
There may be ways to further simplify it, but we'd really need to know what is in the if blocks. For example, if you're just outputting the value, it could get really simple.
If you can create a common Command interface and encapsulate color & id into a Key class you can have a Map of <Key, Command> pairs.
public class Key {
private final String color; // "6" as a color? why not "blue"?
private final String name;
public Key(String color, String name) {
this.color = color;
this.name = name;
}
public String getColor() { return this.color; }
public String getName() { return this.name; }
}
public interface Command {
void execute(Object...args);
}
Map<Key, Command> noSwitch;
for (Key key : noSwitch.keyValues()) {
noSwitch.get(key).execute();
}
Or, better yet, embed that behavior into a polymorphic StockItem class that knows what to do.
Yours looks like a brittle, non-object-oriented design. You can do better.
What you can do, is to create an interface:
interface Do {
whatever()
}
Along with a bunch of implementations for whatever you do inside the different if branches.
Then have a Map of Lists to store and find them:
Map<String, List<Do>> dos = new HashMap();
// put lots of Do implementations in Lists and put them in the map.
After the setup your if monster would be reduced to:
dos.get(id).get(color).whatever
If whats inside the braces is different you can't easily replace it with a for loop (we'd need to see whats inside the braces to be definitive). A switch statement would at least make things look nicer (assuming you use color as an int not a string of an int
if (id.equals("pant")){
switch(color){ //note color should be an int, not a string of an int for this to work
case 1:
//whatevers in the braces
break;
case 2:
//whatevers in the braces
break;
etc
default:
break;
}
}
You could build a map that maps the combinations you are interested in to a function to perform.
Something like:
interface Function {
void f();
}
public void test() {
String color = "1";
String id = "pant";
// Map the string to a function.
Map<String,Function> functions = new HashMap<String,Function>();
// As many of these as you have different processes.
// You could name them too.
functions.put("1|pant",new Function() {
#Override
public void f() {
// What to do when we see color=1 id=pant
System.out.println("1|pant");
}
});
// Pull the function out of the map.
Function f = functions.get(color+"|"+id);
// If it was there.
if ( f != null ) {
// Do it.
f.f();
}
}
I would use the color-tag as an Integer-value-switch:
switch (color){
case 1:
if (id.equals("pant"){}
else if (id.equals("shirt"){}
break;
case 2:
if (id.equals("pant"){}
else if (id.equals("shirt"){}
break;
.
.
.}
easiest way imo.

java loses values from ManagedBeans

I try to write an application to create PDF files, it uses the JavaServer Faces. I struggle with a problem when I give the value of the text box from bean to factory class, the values ​​are lost. I wonder why this happens, already tried many solutions, but they will cause expansion of the code and do not help.
Bean code:
#ManagedBean
#ViewScoped
public class PanelInneBean extends AbstractPanel implements Serializable {
private static final long serialVersionUID = 1L;
private final int CODE = 4;
private boolean use;
private String tytul, opis;
private PdfFactory pdf = PdfFactory.getPdfObject();
public PanelInneBean() {
use = false;
}
public boolean getUse() {
return use;
}
public String getTytul() {
return tytul;
}
public void setTytul(String tytul) {
this.tytul = tytul;
}
public String getOpis() {
return opis;
}
public void setOpis(String opis) {
this.opis = opis;
}
public int getCode() {
return CODE;
}
private void add() {
use = true;
}
public void addBean() {
add();
pdf.addElement(this);
System.out.println("InnePanel after pdf.addElement() this.opis:" + this.opis);
// This sysout prints the correct value after give object to factory
}
}
Factory piece of code:
public int addElement(PdfElement element) {
pdfType = true;
if (element.getUse()) {
elementList.add(element);
return 1;
}
return 0;
}
public void prepare() {
for (PdfElement element : elementList) {
System.out.println("element.code:" + element.getCode());
switch (element.getCode()) {
case 0:
if (nF != null)
break;
nF = new NaglowekFactory(element, Counter.getNumber());
break;
case 1:
if (pF != null)
break;
pF = new ProduktyFactory(element, Counter.getNumber());
prodSum = pF.getProdukty().getSuma();
euroData = pF.getProdukty().getEuroData();
break;
case 2:
if (mF != null)
break;
mF = new MontazFactory(element, Counter.getNumber());
servSum = mF.getMontaz().getSuma();
break;
case 3:
if (uF != null)
break;
uF = new UslugiFactory(element, Counter.getNumber());
asmSum = uF.getUslugi().getSuma();
break;
case 4:
if (iF != null)
break;
iF = new InneFactory(element, Counter.getNumber());
//here Opis value is empty
break;
}
}
System.out.println("factory.prepare() ->");
}
Constructor of InneFactory:
PanelInneBean inne;
public InneFactory(PdfElement element, int order) {
inne = (PanelInneBean) element;
System.out.println("innerFactory constructor, inne.getTytul(): "
+ inne.getTytul());
//here values are empty
this.order = order;
list = new ArrayList<Element>();
}
public int getOrder() {
return order;
}
what I'm doing wrong?
I think you are running into a common misconception about how #ViewScoped beans really work. The bean object itself is created on every Faces request and destroyed after every Faces response.
After the bean is re created however JSF will enter the first lifecycle phase RestoreView. During this phase it will fetch the last good values for this bean from the View State and apply them to the beans Managed Properties.
Basically what is happening is that you are invoking an action, which generates a seperate request than the one that loaded the page, and at this point the reference you added to the PdfFactory is now lost because the PdfFactory in the last object was destroyed!
The best way to resolve this would be to make PdfFactory a Managed Bean. You can initialize the factory in the #PostConstruct method and you can inject other Managed Beans into your PdfFactory bean using the #ManagedProperty annotation.
#ManagedBean
#RequestScoped
public PdfFactory extends ... implements Serializable {
#ManagedProperty("#{myViewBean}")
private MyViewBean viewBean;
#PostConstruct
public initializeFactory() {
//Do stuff
}
public void prepare() {
// prepare stuff
}
}

Categories

Resources