Builder Pattern to build object with static classes - java

I am having a question of building the object in a scenario like ,
#Builder
public class Al {
public Logic logic;
#Value
#Builder
public static class Logic{
public Eq eq;
public Neq neq;
}
#Value
#Builder
public static class Eq{
public Arg1 arg1;
public Arg2 arg2;
}
#Value
#Builder
public static class Neq{
public Arg1 arg1;
public Arg2 arg2;
}
#Value
#Builder
public static class Arg1{
public String myvar;
}
#Value
#Builder
public static class Arg2{
public String val;
}
}
I need to build an object and transform to json similar to
{
"logic": {
"neq": {
"arg1": {
"var": "pos"
},
"arg2": {
"val": "0"
}
}
}
}
Here , neq under logic is decided by one of the condition. Based on the condition , "neq" may be replaced with "eq" and the logic block look as follows
{
"logic": {
"eq": {
"arg1": {
"var": "pos"
},
"arg2": {
"val": "0"
}
}
}
}
While forming the object using builder pattern i use something like
I am interested to know to reduce the duplicate block and making it as single build object.

Related

spring boot dependency Injection with #Cacheable in kotlin, will makes the variable null passed by the superclass super

In kotlin, when I use this way, let bean test2 pass to test3, when I Inject test1, and call test() function, it will get null result when I print test2.
#Service
class Test1(test2: Test2) : Test3(test2) {
#Cacheable(value = ["cacheKey"], key = "#key")
fun cache(key: String): String {
return ""
}
}
#Service
class Test2 {
}
open class Test3(val test2: Test2) {
fun test() {
println(test2)
}
}
but in java, there is no such problem.
#Service
public class JTest1 extends JTest3 {
public JTest1(JTest2 JTest2) {
super(JTest2);
}
#Cacheable(value = "cacheKey", key = "#key")
public String cache(String key) {
return "";
}
}
#Service
public class JTest2 {
}
public class JTest3 {
private final JTest2 JTest2;
public JTest3(JTest2 JTest2) {
this.JTest2 = JTest2;
}
public void test() {
System.out.println(JTest2);
}
}
I decompiled kotlin bytecode, it dose it looks like java class decompiled.
I already figure it out this kotlin issue reason is #Cacheable annotation, it will let spring boot proxy it with cglib.
But I want to known, why only appear in kotlin, what caused the issuse.

Template method and inheritance or composition

I have these classes:
#Data
#AllArgsConstructor
#NoArgsConstructor
public class User {
private String name;
private int age;
}
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Admin {
private String name;
private int age;
}
And I have some operations with template method pattern implementation. Base class with algorithm:
public abstract class Operation<T> {
public void process(T t) {
System.out.println(t);
updateName(t);
System.out.println(t);
}
protected abstract void updateName(T t);
}
Two children with implementation template method:
#Component
public class UserOperation extends Operation<User> {
#Override
protected void updateName(User user) {
String newName = user.getName().toUpperCase();
user.setName(newName);
}
}
#Component
public class AdminOperation extends Operation<Admin> {
#Override
protected void updateName(Admin admin) {
String name = admin.getName();
StringBuilder builder = new StringBuilder();
builder.append(name);
StringBuilder reverse = builder.reverse();
admin.setName(reverse.toString());
}
}
My questions:
How do I rewrite this code to use composition?
Do I understand correctly that when using the template method, I attach to inheritance?
The template method is a great way to avoid duplication. But if it binds me to inheritance, what other ways are there to avoid code duplication? In my example, how can I use composition? (replace the template method with something else?)
1) How do I rewrite this code to use the composition?
The Strategy Pattern is one way. Essentially, you would reverse the relationship between data and operations by passing the operations into the data rather than passing the data into the operations. This is a fundamental change, because "real" objects (with state and behavior) are used instead of data classes.
2) Do I understand correctly that when using the template method, I attach to inheritance?
Yes, the Template Method Pattern is fundamentally based on inheritance.
Instead of template pattern you could have a proxy:
public abstract class Operation<T> {
public abstract void updateName(T t);
}
public class OperationProxy<T> extends Operation<T> {
private final Operation<T> delegate;
public OperationProxy(Operation<T> delegate) {
this.delegate = delegate;
}
#Override
public void updateName(T t){
System.out.println(t);
delegate.updateName(t);
System.out.println(t);
}
}
Note that this would allow you to make class Operation and interface.
UPDATE
Another possibility is defining sequences of operations, and a print operation (even more code):
public interface Operation<T> {
void updateName(T t);
}
public class OperationSequence<T> implements Operation<T> {
private final Operation<T>[] steps;
public OperationSequence(Operation<T>... steps) {
this.steps = steps;
}
#Override
public void updateName(T t){
for (Operation<T> step: steps) {
step.updateName(t);
}
}
}
public class PrintOperation<T> implements Operation<T> {
#Override
public void updateName(T t){
System.out.println(t);
}
}
You can now use the following code:
Operation<MyClass> print = new PrintOperation<>();
Operation<MyClass> seq = new OperationSequence<>(
print, (t) -> {doSomethingWith(t);}, print);

Passing object of multiple types as parameter to a method

Since Java 7, we can catch multiple exceptions in the same catch clause like the following.
try {
...
} catch( IOException | SQLException ex ) {
...
}
Similarly, Is there any way to implement like the following without using Inheritance?
public void passMultipleTypes(Type1 | Type2 obj) {
...
}
The obj object can either be Type1 or Type2. I do not want to use inheritance here as these classes are generated and I cannot change them. So I cannot define them as
public class Test1 extends CommonSuperClass {
...
}
Type1 and Type2 have similar attributes. So I was thinking of working with obj like the following.
public void passMultipleTypes(Type1 | Type2 obj) {
System.out.println(obj.getCode());
System.out.println(obj.getValue());
}
Since classes are generated as part of some code gen plugin.
You can use composition along with inheritance to solve this issue.
Write wrapper class for Type1 and Type2 extending to common interface.
This will provide code reusability as well as act as a layer between apllicaton code and 3rd party API.
public class Testing {
public static void main(String[] args) {
Processor processor = new Processor();
processor.passMultipleTypes(new Type1Wraper());
processor.passMultipleTypes(new Type2Wrapper());
}
}
interface BasicType {
void operationOne();
void operationTwo();
}
class Type1 {
}
class Type2 {
}
class Type1Wraper implements BasicType {
private Type1 type;
#Override
public void operationOne() {
// type 1 method
}
#Override
public void operationTwo() {
// type 1 method
}
}
class Type2Wrapper implements BasicType {
private Type2 type;
#Override
public void operationOne() {
// type 2 method
}
#Override
public void operationTwo() {
// type 2 method
}
}
class Processor {
public void passMultipleTypes(BasicType object) {
object.operationOne();
object.operationTwo();
}
Since you don't want to use inheritance, you could use method overloading.
public void passMultipleTypes(Type1 obj) {
...
}
public void passMultipleTypes(Type2 obj) {
...
}
If you pass an argument of Type1, the first method would be called. If the argument is of Type2, the second would be called.
If you cannot change classes Type1 and Type2 then just use overloading of method:
public void passMultipleTypes(Type1 obj) {
System.out.println(obj.getCode());
System.out.println(obj.getValue());
}
public void passMultipleTypes(Type2 obj) {
System.out.println(obj.getCode());
System.out.println(obj.getValue());
}
"But code duplicates...." yes, that is right. There will be some duplicates of code. But because you cannot change original code then you cannot solve it in nice way. Just move duplication to another place.
You can define a cutom type like Either class in Scala:
class Or<L,R>
{
private final Optional<L> left;
private final Optional<R> right;
...
}
So you can use this class like this:
public void passMultipleTypes(Or<Type1, Type2> obj) {
if(obj.isLeft()) {
} else {
}
}

Building fluent APIs in Java to build testdata for database

Im trying to make a small DSL in Java that I can use to populate testdata in a database. The language I would like to use is as follows.
createRowInTableA().
createRowInTableB().
createRowInTableA().
createRowInTableB().
createRowInTableC().
end();
The order the tables are created is important, for example tableB depends on tableA and tableC depends on tableA and tableB. Therefore I want to make it so that the option to create tableB only is available directly after tableA is created etc. I have started to create the interfaces describing the DSL but I don't know how I should actually implement the interfaces inorder to make the type of nested behavior I'm looking for. This is what the interfaces looks like.
public interface End {
public void sendTestData();
}
public interface TableA extends End {
public Builder createRowInTableA();
}
public interface TableB extends TableA {
public Builder createRowInTableB();
}
public interface TableC extends TableB {
public Builder createRowInTableC();
}
However when I start implementing this language using builder pattern to create a fluent API the hierarchy I want goes away.
public class DBBuilder implements TableC {
static class Builder {
public Builder createRowInTableA(){...}
public Builder createRowInTableB(){...}
public Builder createRowInTableC(){...}
}
}
You can use a set of interfaces and class adapters:
public interface canCreateTableAIf{
public DBBuilderB createRowInTableA()
}
public interface canCreateTableBIf{
public DBBuilderC createRowInTableB()
}
public interface canCreateTableCIf{
public DBBuilderD createRowInTableC()
}
public class canCreateTableA implements canCreateTableAIf (){
public DBBuilderB createRowInTableA(){
...
}
}
public class canCreateTableB implements canCreateTableBIf (){
public DBBuilderC createRowInTableB(){
...
}
}
public class DBBuilderRoot extends canCreateTableA {
}
public class DBBuilderB extends canCreateTableB {
}
public class DBBuilderBCD extends canCreateTableB,canCreateTablec,canCreateTableD {
}
This is not so complicated. But I would check if there is a better way than using fluent Builders. Java 8 for example offers closures. Hier is my suggestion. I've not compiled and tested it. The idea should work but there might be syntax errors.
public class ABuilder
{
private BBuilder subBuilder;
public ABuilder()
{
subBuilder = new BBuilder(this);
}
public BBuilder createRowForA()
{
// your code
return this.subBuilder;
}
public void end()
{
// send test data
}
}
x
public class BBuilder
{
private ABuilder parentBuilder;
private CBuilder subBuilder;
public BBuilder( ABuilder parentBuilder )
{
this.parentBuilder = parentBuilder;
this.subBuilder = new CBuilder(this);
}
public CBuilder createRowForB()
{
// your code
return this.subBuilder;
}
public ABuilder end()
{
return this.parentBuilder;
}
}
x
public class CBuilder
{
private BBuilder parentBuilder;
public CBuilder( BBuilder parentBuilder )
{
this.parentBuilder = parentBuilder;
}
public CBuilder createRowForC()
{
// your code
// I Assume you want to be able to write more than 1 C-row
return this;
}
public BBuilder end()
{
return this.parentBuilder;
}
}
Then you can do:
(new ABuilder())
.createRowForA()
.createRowForB()
.createRowForC()
.end()
.end()
.end();
(new ABuilder())
.createRowForA()
.createRowForB()
.end()
.createRowForB()
.createRowForC()
.end()
.end()
.end();
I'm sure you see more exmples. ;-)

BlazeDS ignoring public accessor on POJO deserialization

I have a POJO class like this:
public class EsigObjectWithDisplayName {
private String objectCode;
private String objectDisplayName;
public EsigObjectWithDisplayName(Locale loc, String objectCode, String objectLocaleCode) {
this.objectCode = objectCode;
this.objectDisplayName = Res.s(loc, objectLocaleCode);
}
public EsigObjectWithDisplayName(){}
public String getObjectCode() {
return objectCode;
}
public String getObjectDisplayName() {
return objectDisplayName;
}
}
and a AS class like this:
package ...
{
[Bindable]
[RemoteClass(alias="...EsigObjectWithDisplayName")]
public class EsigObjectWithDisplayName
{
public var objectCode:String;
public var objectDisplayName:String;
public function toString():String {
return objectDisplayName;
}
}
}
The only way this gets populated is when i modify POJO fields' access to public.
I was under impression that defining public POJO accessors is all that BlazeDS needs for deserialization. What am missing here?
You need both a getter and a setter, see this link:
For Java objects that BlazeDS does not handle implicitly, values found
in public bean properties with get/set methods and public variables
are sent to the client as properties on an Object.

Categories