Since I'm a newbie, I would like to know if there is a better way to code this.
Let say we have batch (spring) where we have downloader/processor/mapper/writer for every type of file we receive since we have customized logic for each file type. X number of Mapper , X number of processor for X number of file types.
Currently looking into templatize the code so not much changes may be required when new type is introduced. Below is my idea. so let say mapper, we have different objects for different file types and all of them will be converted to object of Class CustomObject as below. mapper bean in sample spring context
bean id = "file1Mapper" class = "com.filemapper.file1Mapper"
and it invokes file1Mapper class which has mapping logic. Same for other files.
This is what I'm coming up with to avoid all those file1mapper, file2mapper...... instead one generic mapper which does all together, but looking for better solutions,
public class GMapper{
public <T> CustomObject map(T item){
CustomObject customObject = new CustomObject()
.WithABCDetails(getABCDetails(item));
}
private <T> XYZDetails getABCDetails(T item) {
ABCDetails details = new ABCDetails();
if( item instanceof A){
A a = (A)item;
// read a and map it to ABCDetails object
}
if( item instanceof B){
B b = (B)item;
// read b and map it to ABCDetails object
}
...
...
// repeat this if loop for mapping all file types.
return details;
}
}
Sample jsons
class ABCDetails{
// JsonProperty
Object1 ob1;
Object2 ob2;
Integer d;
}
class Object1{
// JsonProperty
Object3 ob3;
String abc;
String def;
}
class Object2{
// JsonProperty
String ab;
Integer e;
}
class A{
// JsonProperty
String e;
String d; // ex, this is mapped to Object 2 String "ab"
}
This does't look so professional and I believe there might be better ways to do it. Can someone please share an example or explanation on how can this code be made better. I also reading Functional interface to see if that could help.
Thanks in advance.
It is impossible to understand what you need. So I will give some common advice.
Format your code - use tabs/spaces to indent.
Do not put capital letters together - replace ABCDetails with AbcDetails. No one cares how real world name looks like.
Do not write meaningless comments - say no to // JsonProperty
Name variables so that someone can understand what they are supposed to store - avoid {Object1 ob1; Object2 ob2; Integer d;}
Do not write if ... else if ... else if ... or case when ... since this scales badly. Use Map. Examples below.
And a general solution to your problem: use plugin architecture - the best thing (and maybe the only thing) that OOP can offer. Just make all your processors implement common interface. And to work with plugins use dispatcher pattern.
First create all processors.
public interface FileProcessor {
String extension();
void process(String filename);
}
#Component
public final class CsvFileProcessor implements FileProcessor {
public String extension() {
return "csv";
}
public void process(String filename) {
/* do what you need with csv */
}
}
#Component
public final class JsonFileProcessor implements FileProcessor {
public String extension() {
return "json";
}
public void process(String filename) {
/* do what you need with json */
}
}
Then inject them into your dispatcher. Do not forget to process errors, for example, some files may not have suffix, for some files you will not have processor, etc.
#Component
public final class FileDispatcher {
private final Map<String, FileProcessor> processorByExtension;
#Autowired
public FileDispatcher(List<FileProcessor> processors) {
processorByExtension = processors.stream().collect(Collectors.toMap(p -> p.extension(), p -> p));
}
public void dispatch(String filename) {
String extension = filename.split("//.")[1];
processorByExtension.get(extension).process(filename);
}
}
Now if you need to support new file format you have to add only one class - implementation of FileProcessor. You do not have to change any of already created classes.
Related
I'm beginner in Java and I need help. I have several classes.
public class A{
private String name = "A";
public String getClassName(){
return "A";
}
public void editClassName(String name){
this.name = name;
}
}
public class B{
private String name = "B";
private int counter = 0;
public String showClassName(){
return "B";
}
public int getCount(){
return counter;
}
}
Such classes could be more. I also need to have some class witch can return an instance of asked class.
public class ClassSelector{
public static ??? getClassByName(String nameOfClass){
if(nameOfClass == "A"){ return new A();}
if(nameOfClass == "B"){ return new B();}
}
}
And here is a code that I want to use to get access to appropriate class:
ClassSelector.getClassByName("A").getClassName();
ClassSelector.getClassByName("B").showClassName();
I need to have an access to the instance of the class, and each instance can show it's unit methods that class has.
In this situation I don't get which return type I should use in the 'getClassByName' method.
I will very appreciate for help.
I would very much like to offer an alternative architecture if possible! It's not much different to what you have.
Firstly, we'll define some interface.
public interface Named {
String getName();
}
Now, this means you can have lots of concrete classes but provided they implement this interface, you'll know (and the Java compiler will know) that they have the getName method available to you.
Next, let's update your class to implement this interface.
public class A implements Named {
public String getName() {
return "A";
}
}
You could do this for classes B, C... and so on.
Now your method return type can be set to Named, that is:
public class ClassSelector{
public static Named getClassByName(String nameOfClass){
if(nameOfClass.equals("A")){ return new A();}
if(nameOfClass.equals("B")){ return new B();}
}
}
And you can access the response like so:
Named response = ClassSelector.getClassByName("A").getName();
As Eran suggested, it can be only of type Object, because they don't have a common superclass other than Object. If you don't want to work with Object class, you can create a body-less interface and implement it in both(or multiple classes) and that can be your return type.
After the call of the method, you can find the specific type of the returned object with instanceof;
What you are trying to do is called the Factory Pattern.
Assuming you are crating Widgets I suggest;
Introduce a Widget interface and have A and B implement Widget as per Christopher’s answer
Rename ClassSelector to WidgetFactory
Rename the method getClassByName to create, make it non-static and return Widget instances
This is more aligned with common Java name conventions and thus makes your code readily understandable by most developers.
If you want to keep your factory static it is of course possible but it may make your code less testable as it cannot be switched out for another factory in your tests. This is problematic if A and B are heavy weight objects that carries a lot of external dependencies that you may want to exclude.
If testability is a concern you may even consider making the factory implement a WidgetFactory interface...
First of all, please note that for string comparison you have not to use "==" (the problem is in nameOfClass == "A" and so on, I say it only for completeness).
I want suggest a solution based on reflection, that maybe could be more concise:
public interface IClass {
}
public class A implements IClass {
private String name = "A";
}
public class B implements IClass {
private String name = "B";
}
public class ClassSelector {
public static void main(String[] args) {
IClass obj = null;
try {
Class c = Class.forName("A");
obj = (IClass) c.newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
System.out.println("Create object of type " + obj.getClass());
}
}
Thanks to all guys, who have answered my. Forgive me, when I create the first post, I made one mistake, which leads to misunderstanding what I mean. Now the code in the first post is better to show what I'm looking for.
Let's suppose the following scenario:
I have a list of objects of the following type:
public class MyObject {
private String name
private SomeClass someField
private List<Fact> facts
}
The fields name and someField are just to show that the class has some regular members. You can suppose that it's known how to convert these classes to xml.
Fact is an interface where the implementations are not known to me but provided by plugins. Plugins can be required to provide arbitrary code, but I would like to make it as simple as possible.
I want to save and load these objects to xml. Note that while loading the xml, not all implementations may be present (the xml might have been written with a different set of plugins). I want to be able to still read the xml and not lose any information when saving again. In other words: I'm willing add a field such as List<Element> or List<String> to the class and when reading the xml, all parts where a plugin is present should be read into the corresponding Facts, while all parts without a plugin should be stored in an Element or String and when saving again, both lists get saved and could be read by a program having all plugins.
How best to achieve this using JAXB?
One way I can see is to use Map<Class, org.w3c.dom.Element> instead of List<Fact> which can be converted to xml by JaxB and then let any plugin provide custom code converting from and to "their" element using the org.w3c.dom API, but using that API is somewhat cumbersome, so I wonder whether there is a better way?
No idea about best, but one approach that comes close to what you describe is this:
JAXB doesn't work with interfaces; best it can do would be an abstract class. Meaning you need to use List<Object> or List<AbstractFact>. (but you can enforce some restriction in the getter, pluginresolver or afterUnmarshall()).
Your plugin provides the basic classes for the extension (SPI would be the usual approach). You collect them and (after validation) use them to create your JAXBContext. (If you want to support multiple interfaces, maybe provide them by different methods).
In the xml you need to have a type marker like this: <fact xsi:type=\"aFact\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">. If you create the xml with jaxb it will be created autmatically. (The classes need to have the #XmlRootElement annotation).
Here is a stripped down example:
interface Fact {
}
#XmlRootElement
#XmlAccessorType(XmlAccessType.NONE)
class R {
#XmlElement(name = "fact")
private List<Object> facts;
#SuppressWarnings("unchecked")
public List<Fact> getTest() {
if (facts == null) {
facts = new ArrayList<>();
}
return (List<Fact>) (Object) facts;
}
public void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {
// check if all facts implement same interface
for(Object object:facts) {
if (!(object instanceof Fact)) {
throw new IllegalArgumentException("Unsupported type in facts list");
}
}
}
}
#XmlAccessorType(XmlAccessType.NONE)
#XmlRootElement(name = "aFact")
class AFact implements Fact {
#XmlElement
private String a;
public AFact() {
}
public AFact(String a) {
this.a = a;
}
public String getA() {
return a;
}
#Override
public String toString() {
return "AFact [a=" + a + "]";
}
}
public class Jax {
public static void main(String[] args) throws JAXBException {
String xml = "<r><fact xsi:type=\"aFact\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><a>ba</a></fact></r>";
List<Class<?>> contextClasses = new ArrayList<>();
contextClasses.add(R.class);
contextClasses.addAll(getClassesFromPlugin());
JAXBContext context = JAXBContext.newInstance(contextClasses.toArray(new Class<?>[0]));
R entity = (R) context.createUnmarshaller().unmarshal(new StringReader(xml));
System.out.println(entity.getTest());
R r = new R();
r.getTest().add(new AFact("ab"));
context.createMarshaller().marshal(r, System.out);
}
private static List<Class<?>> getClassesFromPlugin() {
List<Class<?>> asList = Arrays.asList(AFact.class);
for(Class<?> cls:asList) {
if (!Fact.class.isAssignableFrom(cls)) {
throw new IllegalArgumentException("Unsupported class");
}
}
return asList;
}
}
I have e.g. object like this:
Original obj = new Original();
And I use from this object e.g. method like(this object has many methods and fields):
obj.getMeYourName();
And I would like to have similar object which is almost same but some methods return something else. I want to solve it by facade.
So, at first I want to create facade and decided if I would return direct object or modified.
What is the best way?
Something like this: ?
Original obj = new Original();
OriginalFacade obj = new OriginalFacade(Original obj, boolean getDirectObject);
OriginalFacade(Original obj, boolean getDirectObject) {
if (getDirectObject) {
return obj //How to convert object into OriginalFacade type?
} else {
obj.setMeYourName("Something else");
return obj; //Howto convert object into OriginalFacade type?
}
}
So, I have 2 problems:
1, is it good solution choose original object or modified original object thru constructor with e.g. boolean getDirectObject?
2, how to easy return original object which must me mapped into OriginalFacade Object
Must I have implement all methods from original object?
Actually, the facade pattern uses a common interface that is used by clients.
For instance:
public interface Facade {
public String getMeYourName();
public void someOtherMethod();
}
public class Original implements Facade {
private String name;
Original(String name) {
this.name = name;
}
public String getMeYourName() {
return name;
}
public void someOtherMethod() {
// a lot of great code
}
}
public class Modified implements Facade {
private Facade original;
private String otherName;
Modified(Facade original, String otherName) {
this.original = original;
this.otherName = otherName;
}
public String getMeYourName() {
return otherName;
}
public void someOtherMethod() {
original.someOtherMethod();
}
}
The clients should only need to see the Facade interface, and shouldn't need to care which actual implementation they are dealing with.
Your code demonstrates you have not understood Facade at all.
In first place Facade should be used to provide a simple interface to complex algorithms.
Second, the facade pattern allows you to access its composed objects, for example:
public class OriginalFacade{
public Original original;
}
Unless you follow the Law of Demeter, this code is perfect valid.
Regardless, if Facade is used, you should not need to access those objects.
The following link explains a little bit of Facade
I recommend you buy and read this book
Facade is not the patter to be used here. It is used to make a complex interface simpler, for example, making out-of-the-box usage patterns.
In your case, why don't you just extend the Original class and overload the methods you want to behave differently?
I have the below use case where I get events containing JsonString1, I have have to do some processing/transformation to get to Object1 through Object 4. As of now I only have one such case and its likely that in future there there might more such hierarchies (atmost 2-3).
I am unable to decide on what would an elegant way to code this.
JsonString1
|
JsonString2
/ \
JsonString3 JsonString4
| |
Object1 Object2
|
Object3
I could just have an Abstract class for processing JsonStrings 1 to 4 and concrete implementation for each type of the event. Something like
public abstract class AbstractEventProcessor {
public AbstractEventProcessor(String jsonString1) {
// Do processing to get JsonString2, JsonString3 and JsonString4
}
}
public class Event1Processor extends AbstractEventProcessor {
Event1Processor(String str) {
super(str);
}
Object1 getObject1() {
}
Object2 getObject2() {
}
Object3 getObject3() {
}
}
And similar implementations more events as they come along.
Is there a better way to do this ?
Also for now two things are constant, but in a rare case might change.
All events will have JsonString1 .. JsonString4 but the number of Objects at the end will vary. But in future this might change.
Although its very unlikely (but not impossible) that the format of the strings might change (say from json to xml)
Do I accomodate for such changes as well by providing interfaces for string transformations, or it this an overkill ?
Usually I am stuck at such places where I am trying to figure out the most elegant way to do this and end up spending a lot of time ? Is there any general advice as well for this ? :)
Thanks
It's not very clear what you exactly want. However, even without it, when I see your hierarchy, it smells. Usually, during my code reviews, whenever I see too fancy hierarchy like yours, there is something wrong in the design.
Try considering using decorators to avoid the inheritance hell. Thus you may create any combinations you may need in the near and far future. Get some inspiration in the standard java class java.io.Reader and its subclasses.
For your case it would mean something like this (at least how I understand your description):
public interface EventProcessor {
public BaseObject processJsonString(String jsonString);
}
public abstract class AbstractEventProcessor implements EventProcessor {
final private EventProcessor processor;
public AbstractEventProcessor(EventProcessor processor) {
this.processor = processor;
}
}
public class SpecialObject1 extends/implements BaseObject { ... }
public class SpecialObject2 extends/implements BaseObject { ... }
public class SpecialObject3 extends/implements BaseObject { ... }
// Each your future processor will look like this
public class Event1Processor extends AbstractEventProcessor implements EventProcessor {
public Event1Processor(EventProcessor processor) {
super(processor);
}
public SpecialObject1 processJsonString(String jsonString) {
final SpecialObject1 result = (SpecialObject1) super.processJsonString(jsonString);
// here you add this Event processor specific stuff
...
return result;
}
// Maybe more methods here
}
public class Client {
public void useEventProcessor() {
final EventProcessor processor1 = new Event1Processor(new Event2Processor(new Event3Processor(null)));
final SpecialObjectX object1 = processor.processJsonString(jsonString);
final EventProcessor processor2 = new Event51Processor(new Event20Processor(new Event2Processor(null)));
final SpecialObjectY object2 = processor2.processJsonString(jsonString);
}
}
I have a service where the flow is basically the following:
Receive an input object. This is just a POJO object and I don't have much say in the design of it.
Convert to a normalized object for my service.
Perform some business logic on the normalized object, and gather some extra data about it.
Convert to an output object for another service that the data gets passed to. (Another POJO.)
Pass the converted data to another service.
What this means, though, is that a good portion of my service is converting from type InputFoo to type NormalizedFoo to type OutputFoo.
This would be a pretty easy task. I'm using the Google Collections library and can have a class like this:
public class InputFooToNormalizedFooConverter implements Function<InputFoo, NormalizedFoo> {
public NormalizedFoo apply(InputFoo input) {
NormalizedFoo output = new NormalizedFoo();
output.setProperty(input.getProperty());
}
}
and another class like this:
public class NormalizedFooFooToOutputFooConverter implements Function<NormalizedFoo, OutputFoo> {
public NormalizedFoo apply(InputFoo input) {
NormalizedFoo output = new NormalizedFoo();
output.setProperty(input.getProperty());
}
}
But each type of Foo essentially has a hierarchy like so:
public class Foo {
List<Bar> barItems;
// .. other properties
}
public class Bar {
List<Baz> bazItems;
List<Quux> quuxItems;
// .. other properties
}
public class Baz {
// .. other properties
}
public class Quux {
// .. other properties
}
This means that I have NormalizedFooToOutputFooConverter that has a NormalizedBarToOutputBarConverter implements Function<NormalizedBar, OutputBar> type and so on and so forth.
Even worse, the input doesn't quite match up exactly to the normalized model. It's more like
public class InputFoo {
public List<InputBar> bars;
public List<InputBaz> bazs;
public List<InputQuux> quuxs;
// .. other properties
}
public class InputBar {
private String barId;
// .. other properties
}
public class InputBaz {
private String barId;
private String bazId;
// .. other properties
}
public class InputQuux {
private String barId;
private String quuxId;
// .. other properties
}
In these models, I can figure out which Baz and Quux belongs to which Bar based on the barId that each one has.
At this point, I have about 20 different converters for going from Input to Normalized and Normalized to Output. And worse still, some of them have name like ReallyLongInputTypeToReallyLongNormalizedTypeConverter creating extremely long class names. I feel like I'm doing something wrong here, with all the converters. Is there a better way to organize my converters?