Java create generalized generic class for composite behavior - java

I m beginner in java, so need your professional suggestions.
Short description:
I have some classes A1, A2, A3 .. B1 ..
I need one magic generic class or method that creates CompositeA CompositeB ...
These composite classes, have defined generalized behavior, what to do with what kind of methods
The kind of methods, could be set by annotations
The methods itself are different for A, B ..
I want to avoid writing CompositeX class every time I have new class X.
The question: Is it possible? If yes, how to?
Long description:
Our problem now:
There are 2+ data sources, like DB, files, libs.
From this data sources we get similar information. For example IDs.
The information is in objects (like hibernate entity), that extends one interface/abstract class.
For example if the content we need is in Foo class, so we have FooDB, FooFile, FooLib. All implementing/extending Foo.
And we create some CombinedFoo, to work with combined data of all this sources.
to update CombinedFoo data source (insert or change some information), only one source will be really used,
for retreiving the data from CombinedFoo all the sources will be used
(see CompositeFoo constructor later)
For example I have a Foo object, that has data (in this case IDs) from DB, another Foo from files and another Foo from some lib.
All this Foo's, implements same Foo interface.
Now I need all the sources in one combined object (that implements Foo interface too).
By initialization of combined foo I do
CompositeFoo compFoo = new CompositeFoo(fooDB, fooFILE, fooLIB)
compFoo.addId("value") calls only fooDB.addId("value").
compFoo.getIds() gets all the ids from all the data sources
(fooDB.getIds() + fooFILE.getIds() + fooLIB.getIds()).
If I want not only Foo, but for example Bar, I need to implement again new CompositeBar, with its own methods (this I want to avoid). But in the end all I need is: to make sure what methods are only for retrieving (get_methods) and what for changing information (set_methods).
now the question:
Is it possible to create such magic generic class, that is written once, and can be applied to every object class, I want to combine?
Here some example for more understanding:
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
//interface used for composite class and data classes
public abstract class Foo {
abstract Set<String> getIds();
abstract void addId(String id);
}
//data source from file
class FooFromFile extends Foo {
#Override
Set<String> getIds() {
//loads data from file
}
#Override
void addId(String id) {
//changes file, add there one id
}
}
//data source from DB
class FooFromDB extends Foo {
#Override
Set<String> getIds() {
//loads ids from DataBase
}
#Override
void addId(String id) {
//adds id to database
}
}
//class i use now, combines all Foo's
//gets info from all, updates only main data source
//this one i want to make generic
class CompositeFoo extends Foo {
private Foo mainFoo;
private Set<Foo> others;
public CompositeFoo(Foo mainSource, Foo ...otherSources ) {
mainFoo = mainSource;
others = new HashSet<>();
Collections.addAll(others, otherSources);
}
#Override
Set<String> getIds() {
HashSet<String> result = new HashSet<>();
//load from main source
result.addAll(mainFoo.getIds());
//and from other sources
for (Foo otherFoo : others ) {
result.addAll(otherFoo.getIds());
}
//ids from all the sources
return result;
}
#Override
void addId(String id) {
//uses only main source, we don't want to add ID to all the sources
mainFoo.addId(id);
}
}
Now it works so:
public static void main(String[] args) {
FooFromDB dbFooMain = new FooFromDB();
FooFromFile fileFoo = new FooFromFile();
CompositeFoo compFoo= new CompositeFoo(dbFooMain, fileFoo);
compFoo.add("new id"); //adds to dbFooMain only
compFoo.getIds(); //gets from all sources (dbFooMain + fileFoo)
}
This magic I want to realize but don't know how:
It should work somehow in this example
public static void main(String[] args) {
FooFromDB dbFooMain = new FooFromDB();
FooFromFile fileFoo = new FooFromFile();
//something like this:
MagicComposite<Foo> compFoo = new MagicComposite<>(dbFooMain, fileFoo);
//or something like this:
Foo compFoo = AnyCompositeFactory.createComposite(Foo.class, dbFoo, fileFoo);
//than this should work
//adds to dbFooMain only. dbFoo.add("new id") called
compFoo.add("new id");
//gets ids from all sources so dbFoo.getIds() + fileFoo.getIds() called and combined
compFoo.getIds();
//-----------------------------------------
//for Bar the same magic class should do
MagicComposite<Bar> compBar = new MagicComposite<>(dbBarMain, fileBar);
//or
Bar compBar = AnyCompositeFactory.createComposite(Bar.class, dbBar, fileBar);
}
So I want to avoid the creating of Composite%ClassName% for every %ClassName% data class.
I need some dynamic, generic CompositeMagic<Class> or whatever.
What I imagine..
If I have Bar class, than I somehow annotate it, what methods are to be combined to get all information, and what methods are just for changing information.
abstract class Bar{
#Magic(Type = retrieveInformationOnly)
Set<String> getSomething();
#Magic(Type = addInformation)
void addSomething(String id);
}
In this case the if I initialize the CombinedBar with some other Bars, and call addSomething() of this composite object, than only main (first arg in constructor) data source should add information, if I call getSomething(), all the initialized classed are called, and combined result is returned. (see CompositeFoo implementation)
The implementation could be something else. Code examples here are just to clarify what I need.

Related

How to use javax.tools.JavaCompiler to create a function that calls a list of methods of child class filtered by custom annotation?

I have this unusual (I think?) situation
public abstract class Base {
public Base() {
// code
}
public final void executeAll() {
final Foo foo = new Foo();
final Bar bar = new Bar();
// now execute all method of "this" that:
// - have annotation mark
// - have return type void
// - accept (foo, bar) has parameters
// - name can be whatever you want
// - protected
}
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD})
protected #interface Mark{
}
}
Now I have a class that extends Base and has some methods with the signature as explained in the executeAll method, like this:
public class Test extends Base {
#Mark
protected void willBeCalled(Foo a, Bar b) {
}
#Mark
protected void alsoThisOne(Foo a, Bar b) {
}
#Mark
protected void yep(Foo a, Bar b) {
}
}
I know that this can be easily achieved my creating an "protected abstract Collection<BiConsumer<Foo, Bar>> getToBeCalled()" make every child to extend it and write the executeAll() method as:
protected abstract Collection<BiConsumer<Foo, Bar>> getToBeCalled();
public final void executeAll() {
final Foo foo = new Foo();
final Bar bar = new Bar();
getToBeCalled().stream.forEach(bic-> bic.accept(foo, bar));
}
But this is not what I want to achieve. I need a way to get the methods to execute from the child class without any major intervention from the developer (that why I thought about an annotation to mark the method desired to be executed and nothing more).
Right now I have a working implementation that inside Base empty constructor scan for every available methods with this.getClass().getMethods(), filter them (must have Mark annotation, accept only a Foo parameter and a Bar parameter in that order and return void, be protected) and save them in a private List<Method> methods; later used by executeAll to call each method.
Recently I also read this: https://www.optaplanner.org/blog/2018/01/09/JavaReflectionButMuchFaster.html ...
... and just-for-fun implemented a MethodHandle version (I think that maybe in my use case will be faster), and planning to make a LambdaMetafactory version... but I'm really intrigued by the javax.tools.JavaCompiler solution. I'm still trying to figuring out how to do it tho... I keep my original method name search and filtering, I keep only the names... and now? How can I convert a list of method names (which I know I have access to, since I'm calling from "this" and are declared protected in the child class, and also have a specific signature) to something usable, like a single private final BiConsumer<Foo, Bar> callAll; computed and saved by the Base() constructor and called by the executeAll function like this:
public abstract class Base {
private final BiConsumer<Foo, Bar> callAll;
protected Base() {
// get all methods <<< already done
Method[] methods = ;
// filter them by annotation, visibility and signature <<< already done
List<Method> filtered> = ;
// save only the names <<< already done
List<String> names = ;
// use javax.tools.JavaCompiler somehow <<< I miss this
callAll = ???;
}
public final void executeAll() {
final Foo foo = new Foo();
final Bar bar = new Bar();
callAll.accept(foo, bar);
}
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD})
protected #interface Mark{
}
}
Of course the idea to use a BiConsumer as callAll is just an idea if there is something better I'm perfectly fine with suggestion.

JAVA Is it possible to dynamically have a class extend another?

I've been at this since yesterday looking for a way to do this. What I have are hundreds of POJOs from a third party and need to apply properties to these based on business rules. I'm avoiding the altering of the POJOs because the third party could potentially recreate them thus creating a nightmare for managing files down the road.
What I'm attempting to do is to dynamically have a class extend another class.
For example.
POJO: Foo.java
package abc.service;
public class Foo {
private String greeting = "";
public Foo(){
gretting = "Good morning";
}
public String getGreeting(){
return greeting;
}
}
// end file
Mine: Bar.java
package abc.service;
public class Bar {
private String claim = "";
public Bar(){
claim = "You're correct";
}
public String getClaim(){
return claim;
}
}
// end file
Mine: TestMe.java
Trying here in a class separate from the POJOs to have a POJO extend another of my classes.
Is this beyond the abilities of JAVA?
package abc;
public class TestMe {
Foo f = new Foo();
Class c1 = f.getClass();
Bar b = new Bar();
Class c2 = b.getClass();
Class merged = c2.asSubclass(c1);
// Trying to call the Foo method
System.out.println(merged.getGreeting());
// Trying to call the Bar method
System.out.println(merged.getClaim());
}
Additionally what is going on is that JSON schemas are being created from the POJOs that are provided. But the POJOs are only based on an UPDATE record scenario. I'm looking for the best way to have the POJOs extend another class for CREATE record scenarios which is why I'm looking to dynamically have their POJOs extend my code when required.
Need to generate json schema for the POJOs for UPDATE
Need to verifying their json meets the POJOs requirements for UPDATE
Need to convert their json to the POJOs for UPDATE
Also,
Need to generate json schema for the POJOs for CREATE
Need to verifying their json meets the POJOs requirements for CREATE
Need to convert their json to the POJOs for CREATE
Using Jackson Mixin and the ObjectMapper I'm able to dynamically apply my code to the classes when creating the schemas but the issue I'm having is when trying to have the POJOs extend the class where Mixin is not going to solve the issue.
With plain Java: no, it can't be done.
You can change byte code, either in the build process, or at runtime. But it's hard, and there's not a lot of documentation.
AspectJ's declare parents expression is probably the easiest way to do it at build time.
If you want to do it at runtime, look at frameworks like asm, CGLib or ByteBuddy. But you will have to run the code from inside a custom ClassLoader or agent.
You can use composition instead of inheritance.
public class Foo {
private String greeting = "";
public Foo(){
gretting = "Good morning";
}
public String getGreeting(){
return greeting;
}
}
Your class
public class Bar {
private String claim = "";
private Foo foo;
public Bar(){
claim = "You're correct";
foo = new Foo();
}
public String getClaim(){
return claim;
}
public Foo getFoo(){
return foo;
}
}
And the test
public class TestMe {
// Trying to call the Foo method
System.out.println(bar.getFoo().getGreeting());
// Trying to call the Bar method
System.out.println(bar.getClaim());
}
Or you can do you class a little bit different.
public class Bar {
private String claim = "";
private Foo foo;
public Bar(){
claim = "You're correct";
foo = new Foo();
}
public String getClaim(){
return claim;
}
public String getGreeting(){
return foo.getGreeting();
}
}
And the test
public class TestMe {
// Trying to call the Foo method
System.out.println(bar.getGreeting());
// Trying to call the Bar method
System.out.println(bar.getClaim());
}
It is Not Possible.
Simply to put, JAVA at present(till latest version) does not have a provision to dynamically extend the class at runtime and load to JVM.
Instead of extending, you should use a design pattern. For example the Stategy Pattern. This allows you to change your strategy dynamicaly.

need C++ template-like functionality in Java

In my program, I've got the following class hierarchy:
public abstract class Effect
{
// ...
}
public class Effect1 extends Effect
{
public static final NAME = "blah blah 1";
// ...
}
public class Effect2 extends Effect
{
public static final NAME = "blah blah 2";
// ...
}
(many more EffectN classes with quite different implementations). Later on, I've got another family of classes using those EffectN's :
public abstract class EffectList
{
protected Effect mEffect;
// ...
}
public class EffectList1 extends EffectList
{
public static final N = Effect1.NAME;
public EffectList1
{
mEffect = new Effect1();
}
// ...
}
public class EffectList2 extends EffectList
{
public static final N = Effect2.NAME;
public EffectList2
{
mEffect = new Effect2();
}
// ...
}
(many more of those EffectListN classes, one for each EffectN).
Now, while the EffectN's really do have quite different implementations, all the EffectListN's are (nearly) identical - the only difference between them is shown above.
Now, had this been C++, all the EffectListN classes would be easily generated with just 1 template, but AFAIK (being quite new to Java) Java generics cannot do this job, can it?
Any suggestions?
Are you trying to create generic way to call constructor? If so this could be done by reflection as long as all implementation would supply the same kind of arguments e.g. default constructor:
class EffectList<EffectType extends Effect> {
public EffectList(Class<EffectType> clazz) {
try {
mEffect = clazz.getConstructor().newInstance();
} catch (Exception ex) {
// suppressing Exceptions - in production code you should handle it better
throw new RuntimeException(ex);
}
// ...
}
// ...
}
then use it like that:
EffectList<Effect1> effectList1 = new EffectList(Effect1.class);
EffectList<Effect2> effectList2 = new EffectList(Effect2.class);
The static field however cannot be handled such way - best you can do is make it an instance variable and obtain the value via reflection as well:
clazz.getDeclaredField("NAME").get(null); // null is used to obtain static fields
Reason why static field cannot be handled is that there would be only one variable shared among all EffectLists (since underneath its only just one class with just compile-time checks added).
I don't know how you would do it with C++, but going off your description, no, Java generics would not be able to handle this.
For one, you have static fields that depend on other static fields defined in the EffectN types. There's nothing in Java which sets a restriction that a type should have a static field. You wouldn't be able to dynamically set
public static final N = SomeEffect.NAME;
Second, because of type erasure, you would not be able to do
public EffectList2
{
mEffect = new SomeEffect(); // assuming SomeEffect is the type parameter
}
you'd need to pass in a Class instance and use reflection to instantiate this type.

How to implement GWT Editor with sub-editors

I am trying to create a GWT Editor for a bean Object, which has two fields of another Object type, therefore I want sub-editors for those fields. The problem is that I am quite new to the editors framework, and I don't really get the idea of all those Editor interfaces out there.
Please advise of the best solution. My ideas were the following: using drivers of sub-editors to pass data to main editor driver; or use some sort of CompositeEditor (but I didn't know what to do with overridden methods...).
Here's a sample code:
public class A {
String s1, s2;
Integer i;
Double d;
B ba, bb;
}
public class B {
BigDecimal a, b;
}
//sub-editor
public class BEditor extends Composite implements Editor<B> {
interface BDriver extends BeanEditorDriver<B, BEditor> {
}
//implements HasEditorErrors interface
ValueBoxEditorDecorator<BigDecimal> a, b;
}
//main editor
public class AEditor extends Composite implements Editor<A> {
interface ADriver extends BeanEditorDriver<A, AEditor> {
}
private ADriver driver = GWT.create(ADriver.class);
ValueBoxEditorDecorator<String> s1, s2;
ValueBoxEditorDecorator<Integer> i;
ValueBoxEditorDecorator<Double> d;
BEditor ba, bb;
public AEditor() {
driver.initialize(this);
driver.edit(new A());
}
//called when the editor form is submitted
public void onSubmit() {
driver.clearErrors();
A a = driver.flush();
// A has both B fields = null
// AEditor successfully displays validation errors,
// but BEditors do not display errors, nor does
// ADriver get any errors from BEditor
}
}
}
When you create the VehiculeDTO, also create B subclasses :
A a = new A();
a.setBa(new B());
a.setBb(new B());
driver.edit(a);
Here are some guidelines from my experiences using the Editor Framework, both personally, and also in industry. I have tried my best to make them relevant to your example.
Identify your "top-level" editor. In your case, it would be AEditor - in most other cases, it would be a view. Have the designated widget implement the Editor interface, with type param = your backing object (which you have done correctly).
Ensure your backing object A includes getters and setters and the fields are private. You have left them with default access which I don't think is a good idea.
Ensure your top level widget contains a sub-editor for each of the fields in A. They should share the same name as the corresponding field in A, or be annotated with #Path to indicate which field they relate to.
Your sub-editors should never have their own driver interface. They should either implement LeafValueEditor, ValueAwareEditor etc or an adapter interface such as IsEditor
In the constructor for your top level editor (here, AEditor), you need to initialise the driver and backing object:
ADriver driver = GWT.create(ADriver.class);
public AEditor {
driver.initialize(this);
driver.edit(new A());
}
When you save, you should be calling driver.flush() to move the data from the top level editor into the backing object. Conversely, when you load, you should be calling driver.edit() with the backing object you wish to load
I have put up some Gists to demonstrate LeafValueEditor and IsEditor, in case you need help changing your sub-editor:
LeafValueEditor
IsEditor

help with a function

I am trying to add information from main()
to an items class where i am storing the information in a 3 different hashsets
i have 3 classes
project - main()
libaray - addBandMembers function
Item - addband(String... member)
i am adding CD information.
first, i add band, # of songs, title - which works good
Where i am having a problem is adding band members..
I think i need to cast musicCD object to CD class then invoke the
addband function?
Im just not sure how to do that.
Here is the parts of code i think you will need to help me..
this is what i have:
Main()
item = library.addMusicCD("Don't Let Go", "Jerry Garcia Band", 15, "acid rock", "jam bands");
if (item != null) {
library.addBandMembers(item, "Jerry Garcia", "Keith Godcheaux");
library.printItem(out, item);
}
Then, here the first function thats called..
This is where i need help!!!!
public void addBandMembers(Item musicCD, String... members)
{
//musicCD.addband(members); // both cant find addband function..
//Item.addband(members);
}
Then in another class i am trying to add the information..
private String [] members;
public void addband(String... member)
{
this.members = member;
}
oh ya, here is my set..
public class Library
{
private Set<CD> theCDs = new HashSet<CD>();
private Set<DVD> theDVDs = new HashSet<DVD>();
private Set<Book> theBooks = new HashSet<Book>();
So, from the function public void addBandMembers()
i am trying to add members to addband
is my addband function wrong?
I do have a background in C++ and i am trying to apply what i know to java so please be nice. I know i have some more reviewing to do i just cant find what i need on the web..
Thank you..
There appears to be several issues you need to address...
First, in addBandMembers(), if it can't find musicCD.addBand then you either need to define the addBand() method for Item or find the appropriate class that has an addBand() method based on the objects that you can access from Item.
Second, you need to understand the difference between class methods and object methods. Class methods, identified by the "static" keyword, operate on the base class in a way that's shared by all instantiated objects of that class. For example, static foo(x){ this.x = x; } would set the class's static "x" variable, and any access to the "x" variable will use the last set value from calling foo() (assuming no other ways to set x). So, if you have object1 and object2, both of the class that defines foo, object1.x and object2.x would be the same location in memory, both set at the same time when calling foo(). Instance variables, identified by the distinctly missing "static" keyword, are not shared. public bar(y){ this.y = y; } would set a different location in memory for each object of the class - object1.y would be a different memory location, and a (potentially) different value than object2.y.
Third, "Item" is a rather non-descriptive name. Is your library guaranteed to always be for music, or do you need to be more generic? Renaming the class to either LibraryItem or Media (as suggested in another answer) would clarify your code.
Fourth, you didn't provide nearly enough information to really diagnose what's going on. When you ask for help, you should provide relevant output (what gets printed at the end of main?), classes where relevant variables/functions are defined (where are the addband() and addBandMembers() functions defined?) and any error messages (what error do you get when you uncomment either line within addband()?). With complete information, it's much easier for people to help. Without complete information, it's often impossible for people to give really good answers.
Fifth, you talk about casting to Object but mention you don't know how. Casting in Java is very similar to casting in C++ : Foo myFoo = (Foo)myBar;. You'll get a ClassCastException at runtime if myBar is not a subclass of myFoo and myFoo is not a subclass of myBar. Note that you don't need to cast subclasses to their superclasses, as the JVM already knows the class heirarchy, just like the compiler knows in C++. All classes in Java inherit from Object, so there's almost never a need to cast to Object. On the other hand, if you happen to have a subclass of Item where addband() is defined, you can cast item (in main) to the appropriate subclass, and call the addband() method on the casted object.
CompactDisk cd = (CompactDisk)item;
cd.addband(...);
or you can do it as a one-liner as
((CompactDisk)cd).addband(...);
The first one would be useful if you need to use the object as a CompactDisk more than once. The second one would be acceptable if you only need to cast once, maybe twice both next to each other - more than that, creates readability and maintenance problems.
There are a lot of things that don't make sense in this question. Add suggests increasing the number of items in a collection. So addBandMembers should mean you are adding Band members to a band. so I would expect there to be a Band class that contained that method. It should look something like addBandMembers(Set<BandMember> bandMembers) Your addMusicCD is definitley an acceptable way of adding a item to a collection, but requires some value for each parameter, therefore you may want to require just a CD whose constructor can have those specific parameters required.
I would suggest a base class for your media possibly called media that might have a Band property and all other basic properties common to all the types of media. Then you can inherit from the media class in your CD, DVD and Book classes and add specific properties to those media types.
This should get you started.
If by
//musicCD.addband(members); // both cant find addband function..
//Item.addband(members);
You mean that it won't compile then probably the other class where you have
private String [] members;
public void addband(String... member)
{
this.members = member;
}
is not the Item class. That is why musicCd.addband(members) won't work as musicCD is an Item. Item.addband(members) won't work as addband is not a static method.
If I understood correctly the addband method is on your CD class. You should have something like this to make it work.
Note: If you 15 is the CD price, then you should consider using BigDecimal instead of int, double or whatever you are using. If it was something else then change the BigDecimal for and int/double and its corresponding parameter name.
Also, I assumed that the out parameter was a PrintStream
import java.math.BigDecimal;
public class Main {
public static void main(String[] args) {
Band band = new Band("Jerry Garcia Band");
band.addMember("Jerry Garcia");
band.addMember("Keith Godcheaux");
MusicCD cd = new MusicCD("Don't Let Go", band, new BigDecimal(15),
"acid rock", "jam bands");
Library library = new Library();
library.addMusicCD(cd);
library.printItem(System.out, cd);
}
}
public interface Item {
}
public class Book implements Item {
}
public class DVD implements Item {
}
public abstract class CD implements Item{
private String title;
private BigDecimal price;
private String information;
public CD(String title, BigDecimal price, String information) {
this.title = title;
this.price = price;
this.information = information;
}
}
import java.util.HashSet;
import java.util.Set;
public class Band {
private Set<String> members;
private String name;
public Band(String name) {
this.members = new HashSet<String>();
}
public void addMember(String member) {
members.add(member);
}
}
import java.io.PrintStream;
import java.util.HashSet;
import java.util.Set;
public class Library {
private Set<CD> theCDs = new HashSet<CD>();
private Set<DVD> theDVDs = new HashSet<DVD>();
private Set<Book> theBooks = new HashSet<Book>();
public void addMusicCD(MusicCD cd) {
theCDs.add(cd);
}
public void printItem(PrintStream out, Item item) {
out.print(item);
}
}
I am sure things can be added to this. I tried not change it a lot so you could understand what was needed.

Categories