How to run code after constructor in a Lombok builder - java

I have a class that I want to use Lombok.Builder and I need pre-process of some parameters. Something like this:
#Builder
public class Foo {
public String val1;
public int val2;
public List<String> listValues;
public void init(){
// do some checks with the values.
}
}
normally I would just call init() on a NoArg constructor, but with the generated builder I'm unable to do so. Is there a way for this init be called by the generated builder? For example build() would generate a code like:
public Foo build() {
Foo foo = Foo(params....)
foo.init();
return foo;
}
I'm aware that I can manually code the all args constructor, that the Builder will call through it and I can call init inside there.
But that is a sub-optimal solution as my class will likely have new fields added every once in a while which would mean changing the constructor too.

In Foo you could manually add a constructor, have that do the initialization, and put #Builder on the constructor. I know that you already know this, but I think it is the right solution, and you won't forget to add the parameter since you do want to use the code in the builder anyway.
Disclosure: I am a lombok developer.

After much trial and end error I found a suitable solution: extend the generate builder and call init() myself.
Example:
#Builder(toBuilder = true, builderClassName = "FooInternalBuilder", builderMethodName = "internalBuilder")
public class Foo {
public String val1;
public int val2;
#Singular public List<String> listValues;
void init() {
// perform values initialisation
}
public static Builder builder() {
return new Builder();
}
public static class Builder extends FooInternalBuilder {
Builder() {
super();
}
#Override public Foo build() {
Foo foo = super.build();
foo.init();
return foo;
}
}
}

I just stumbled upon the same issue. But additionally, I wanted to add an method buildOptional() to the builder to not repeat Optional.of(Foo) each time I need it. This did not work with the approach posted before because the chained methods return FooInternalBuilder objects; and putting buildOptional() into FooInternalBuilder would miss the init() method execution in Builder...
Also, I personally did not like the presence of 2 builder classes.
Here is what I did instead:
#Builder(buildMethodName = "buildInternal")
#ToString
public class Foo {
public String val1;
public int val2;
#Singular public List<String> listValues;
public void init(){
// do some checks with the values.
}
/** Add some functionality to the generated builder class */
public static class FooBuilder {
public Optional<Foo> buildOptional() {
return Optional.of(this.build());
}
public Foo build() {
Foo foo = this.buildInternal();
foo.init();
return foo;
}
}
}
You can do a quick test with this main method:
public static void main(String[] args) {
Foo foo = Foo.builder().val1("String").val2(14)
.listValue("1").listValue("2").build();
System.out.println(foo);
Optional<Foo> fooOpt = Foo.builder().val1("String").val2(14)
.listValue("1").listValue("2").buildOptional();
System.out.println(fooOpt);
}
Doing so let's you add what I want:
Add an init() method which is executed after each object construction automatically
Adding new fields do not require additional work (as it would be for an individually written constructor)
Possibility to add additional functionality (incl. the init() execution)
Retain the complete
standard functionality the #Builder annotation brings
Don't expose an additional builder class
Even if you solved your problem before I like to share this as the solution. It is a bit shorter and adds a (for me) nice feature.

This works for me, not a complete solution, but quick and easy.
#Builder
#AllArgsConstructor
public class Foo {
#Builder.Default
int bar = 42;
Foo init() {
// perform values initialisation
bar = 451; // replaces 314
return foo;
}
static Foo test() {
return new FooBuilder() // defaults to 42
.bar(314) // replaces 42 with 314
.build()
.init(); // replaces 314 with 451
}
}

Related

Evaluate parameter passed to mocked method called from another class

I am testing a class that use another class I have mocked. One of the outer classes' methods modifies an argument that is passed to the mocked class's method, and I need to check that it was modified correctly.
The code looks something like this:
public class Foo
{
public boolean performTask(String name, Integer version)
{
...
}
}
public class Bar
{
private Foo foo;
public Bar(Foo foo)
{
this.foo = foo;
}
public void doSomething(String name, Integer version)
{
boolean good = foo.performTask(name, ((version.startsWith("A")) ? null : version));
...
}
}
I need to check that if I pass a name argument that starts with A, then the second argument being passed to performTask() is null.
Edit:
As requested, this the start of the unit test:
public class BarTest
{
#Mock
private Foo mockFoo;
#Before
public void setup() throws Exception
{
MockitoAnnotations.initMocks(this);
}
#Test
public void test() throws Exception
{
Bar bar = new Bar(mockFoo);
bar.doSomething("ABC", new Integer(1));
}
}
All the examples I've seen of using verify involve calling the mock class directly. How do I use it in this case?
Exactly like that. All you need is access to the mock, which you have.
Mockito.verify(mockFoo, Mockito.times(1)).performTask("ABC", null);
If its important what the method is supposed to return (by default false),
you will need to define the behaviour using:
Mockito.when(mockFoo.performTask("ABC", null)).thenReturn(true);
Example:
#Test
public void test() throws Exception {
Mockito.when(mockFoo.performTask("ABC", null)).thenReturn(true);
Bar bar = new Bar(mockFoo);
bar.doSomething("ABC", new Integer(1));
Mockito.verify(mockFoo, Mockito.times(1)).performTask("ABC", null);
}

How to nest methods in java to force user to use the nested name?

I'm writing a library, for more readability I want to force user to use nested methods to call the correct functions.
For example this is my class looks like:
public class Foo{
public void methodA(){}
public void methodB(){}
public void methodC(){}
}
What I'm expecting the user:
Foo foo = new Foo();
foo.methodA.methodB();
foo.methodA.methodC();
to call method B & C through calling the methodA as a prefix
After reading your question i think you are asking about Builder Design patten in which every methods return type is same class object and you can make call hierarchy like this.
obj.aMethod().bMethod().cMethod();
in your example just do like this:
public class Foo{
private static final Foo instance = new Foo();
private Foo(){}
public static Foo getInstance(){
return instance;
}
public Foo methodA(){
//Do stuff
return getInstance();
}
public Foo methodB(){}
public Foo methodC(){}
}
Now you can call like objfoo.getInstance().methodA().methodB();
Hope it will help you. To read more about that pattern
To force the user to use methodA to access methodB you could use an inner class.
In methodB you can access the Foo-Object with Foo.this.
public class Foo{
public Bar methodA()
{
// ...
return new Bar();
}
public class Bar {
private Bar() {}; // only methodA can create a Bar object
public void methodB(){}
public void methodC(){}
}
}
This is called as method chaining. You will need to set the return type of all methods as the same as the Class.
public class Foo{
public Foo methodA()
public Foo methodB()
public Foo methodC()
}
Now the client can simply call:
foo.methodA().methodB(), etc.
You can have one "terminal method" i.e. one that does not return a value. For example
public void methodD();
This method will be called last.
foo.methodA().methodB().methodC().method();
This line in itself will be valid as return type is void.
Please look at method chaining/ builder pattern YouTube videos, it will be clear.

Java - "intercept" a private method

I know this has been asked before, and the answer is usually "you can't" and/or "don't," but I'm trying this anyway.
The context is that I'm trying to set up some "black magic" to aid in testing. My code is running ultimately under JUnit and the nature of the system is such that, while I have access to most any library I could want (ByteBuddy, Javassist, etc), I can't play around with the code prior to it running, I'm stuck with working with classes on the fly.
Here's the setup:
// External Library that I have no control over:
package com.external.stuff;
/** This is the thing I ultimately want to capture a specific instance of. */
public class Target {...}
public interface IFace {
void someMethod();
}
class IFaceImpl {
#Override
void someMethod() {
...
Target t = getTarget(...);
doSomethingWithTarget(t);
...
}
private Target getTarget() {...}
private void doSomethingWithTarget(Target t) {...}
}
Within my test magic-ness, I have an instance of IFace, which I happen to know is an IFaceImpl. What I'd like to do is be able to steal the instance of Target produced internally. Effectively, this would have the same effect as the following (if private methods were overrideable):
class MyIFaceImpl extends IFaceImpl{
private Consumer<Target> targetStealer;
#Override
void someMethod() {
...
Target t = getTarget(...);
doSomethingWithTarget(t);
...
}
/** "Override" either this method or the next one. */
private Target getTarget() {
Target t = super.getTarget();
targetStealer.accept(t);
return t;
}
private void doSomethingWithTarget(Target t) {
targetStealer.accept(t);
super.doSomethingWithTarget(t);
}
}
But, of course, that doesn't work as private methods cannot be overridden.
So the next type of approach would be something like ByteBuddy or Javassist
public static class Interceptor {
private final Consumer<Target> targetStealer;
// ctor elided
public void doSomethingWithTarget(Target t) {
targetStealer.accept(t);
}
}
/** Using ByteBuddy. */
IFace byteBuddyBlackMagic(
IFace iface /* known IFaceImpl*/,
Consumer<Target> targetStealer) {
return (IFace) new ByteBuddy()
.subClass(iface.getClass())
.method(ElementMatchers.named("doSomethingWithTarget"))
.intercept(MethodDelegation.to(new Interceptor(t))
.make()
.load(...)
.getLoaded()
.newInstance()
}
/** Or, using Javassist */
IFace javassistBlackMagic(
IFace iface /* known IFaceImpl*/,
Consumer<Target> targetStealer) {
ProxyFactory factory = new ProxyFactory();
factory.setSuperClass(iface.getClass());
Class subClass = factory.createClass();
IFace = (IFace) subClass.newInstance();
MethodHandler handler =
new MethodHandler() {
#Override
public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
if (thisMethod.getName().equals("doSomethingWithTarget")) {
consumer.accept((Target) args[0]);
}
return proceed.invoke(self, args);
}
};
((ProxyObject) instance).setHandler(handler);
return instance;
}
and as I was testing out these pattern, it worked in other cases where the method I wanted to intercept was package-local, but not for private methods (expected for ByteBuddy, per the documentation).
So, yes, I recognize that this is attempting to invoke dark powers, and that this is normally frowned upon. The question remains, is this doable?
using javassist you can instrument the someMethod( ) in the IClassImpl class to send the instance of the TargetClass to someother class and store it there or do other manipulations using the instance created.
this can be achieved using the insertAfter( ) method in javassist .
For example :
method.insertAfter( "TestClass.storeTargetInst(t)" ); // t is the instance of Target class in IClassImpl.someMethod
TestClass{
public static void storeTargetInst(Object o){ ### code to store instance ###}
}
The insertAfter() method injects a line of code before the return statement of a method or as the last line of a method in case of void methods.
Refer this link for more information on the methods available for instrumentation.
Hope this helps!
If you can execute some code in like public static void main block, or just before IFaceImpl is loaded, then you can use javassist to edit that class directly before it is loaded - so you can change method to be public, add another one, etc:
public class Main {
public static void main(String[] args) throws Exception {
// this would return "original"
// System.out.println(IFace.getIFace().getName());
// IFaceImpl class is not yet loaded by jvm
CtClass ctClass = ClassPool.getDefault().get("lib.IFaceImpl");
CtMethod getTargetMethod = ctClass.getDeclaredMethod("getTarget");
getTargetMethod.setBody("{ return app.Main.myTarget(); }");
ctClass.toClass(); // now we load our modified class
// yay!
System.out.println(IFace.getIFace().getName());
}
public static Target myTarget() {
return new Target("modified");
}
}
where library code is like this:
public interface IFace {
String getName();
static IFace getIFace() {
return new IFaceImpl();
}
}
class IFaceImpl implements IFace {
#Override public String getName() {
return getTarget().getName();
}
private Target getTarget() {
return new Target("original");
}
}
public class Target {
private final String name;
public Target(String name) {this.name = name;}
public String getName() { return this.name; }
}
If there is no way to execute your code before that class is loaded, then you need to use instrumentalization, I will use byte-buddy-agent library to make this simpler:
public class Main {
public static void main(String[] args) throws Exception {
// prints "original"
System.out.println(IFace.getIFace().getName());
Instrumentation instrumentation = ByteBuddyAgent.install();
Class<?> implClass = IFace.getIFace().getClass();
CtClass ctClass = ClassPool.getDefault().get(implClass.getName());
CtMethod getTargetMethod = ctClass.getDeclaredMethod("getTarget");
getTargetMethod.setBody("{ return app.Main.myTarget(); }");
instrumentation.redefineClasses(new ClassDefinition(implClass, ctClass.toBytecode()));
// yay!
System.out.println(IFace.getIFace().getName());
}
public static Target myTarget() {
return new Target("modified");
}
}
Both versions might be much more problematic to run on java 9 and above due to how modules work, you might need to add additional startup flags.
Note that on java 8 instrumentalization might not be present on client JRE. (but with few more hacks can be added, even at runtime)

Read only objects produced by a factory in Java

In previous C++ code I've used friend classes when creating a factory that can output "read only" objects which means that as the objects are consumed throughout the code there is no risk that they can be inadvertently changed/corrupted.
Is there is there a similar way to implement this in Java or am I being overly defensive?
Make use of the final keyword. This keyword can mark a class/methods as non-extendable, and mark fields/variables as non-mutable.
You will hide the default constructor of the object using the private constructor, and force parameterised constructors which will initialise all necessary final fields.
Your only problem is that the factory is kind of redundant. Since all fields of the object are final, you will have to use all factory methods at object build-time.
Example:
public final class DataObject
{
protected final String name;
protected final String payload;
private DataObject()
{
}
public DataObject(final String name, final String payload)
{
this.name = name;
this.payload = payload;
}
}
// Using the factory
DataObject factory = new Factory().setName("Name").setPayload("Payload").build();
// As opposed to
DataObject dao = new DataObject("Name", "Payload");
// ==> Factory becomes redundant, only adding extra code
Solution without final:
I'm afraid you will have to forget about the immutability mechanism of C++. The factory pattern is never a bad choice if you have huge data objects (i.e. with a lot of setters), but you can't really avoid mutability of the constructed object. What you could do, is make the data object an inner class of the factory, and make the setters private. That way, ONLY the factory can access the setters. This would be the best approach for you (i.e. simulate immutability).
Example:
public class Factory
{
private String name;
private String payload;
public Factory setName(final String name)
{
this.name = name;
}
public Factory setPayload(final String payload)
{
this.payload = payload;
}
public DataObject build()
{
DataObject newObj = new DataObject();
newObj.setName( this.name );
newObj.setPayload( this.payload );
return newObj;
}
public class DataObject
{
// fields and setters, ALL PRIVATE
}
}
You can either put the object class and factory in the same package, and make the mutable methods package-scoped (this is the default visibility in Java, simply don't declare the methods to be public, private or protected), or make the class truly immutable and do all the work in the constructor. If you find that there are too many arguments in the constructor and it is difficult to understand, consider the Builder Pattern.
There is no direct equal to friend classes in Java. However have a look at http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html.
If your object implements an interface and the factory returns interface type rather than the concrete type (which is better) then you can use java.lang.reflect.Proxy to create dynamic proxy at runtime that intercepts all method calls to the target object. As in the following code example FooFactory class creates a Foo instance (every time its createFoo method is called) but does not directly return instance but instead returns a dynamic proxy that implements the same interface as Foo and dynamic proxy intercepts and delegates all method calls to the Foo instance. This mechanism can be helpful to control access to a class when you dont have class code.
public class FooFactory {
public static IF createFoo() {
//Create Foo instance
Foo target = new Foo(); // Implements interface IF
//Create a dynamic proxy that intercepts method calls to the Foo instance
IF fooProxy = (IF) Proxy.newProxyInstance(IF.class.getClassLoader(),
new Class[] { IF.class }, new IFInvocationHandler(target));
return fooProxy;
}
}
class IFInvocationHandler implements InvocationHandler {
private Foo foo;
IFInvocationHandler(Foo foo) {
this.foo = foo;
}
#Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if (method.getName().equals("setMethod")) {
// Block call
throw new IllegalAccessException();
} else {
// Allow call
method.invoke(proxy, args);
}
return null;
}
}
class Foo implements IF {
public void setMethod() {
} // method that is not allowed to call
public void getMethod() {
}
}
interface IF {
void setMethod(); // method that is not allowed to call
void getMethod(); // method that is allowed to call
}
The closest thing to a C++ friend class in Java is package-private access.
SomeObject.java:
package somewhere.someobjandfriends;
public class SomeObject {
Object aField; // field and constructor
SomeObject() {} // are package-only access
public void aMethod() {
System.out.println(this);
}
}
SomeObjFactory.java:
package somewhere.someobjandfriends;
public class SomeObjFactory {
public SomeObject newHelloWorld() {
return new SomeObject() {
{
aField = "hello world!";
}
#Override
public String toString() {
return aField.toString();
}
};
}
}
Anywhere outside of the package can see SomeObject and aMethod but can only create new instances through the factory.

Guice: injecting a parameter used in implementation of abstract method

Here is an example of the issue I've come across:
public interface IFoo { ... }
public abstract class Helper implements IFoo {
public Helper() { ... }
protected abstract X helperMethod();
}
public class Foo extends Helper {
private final String aaa;
#Inject
public Foo(String aaa) { this.aaa = aaa; }
#Override
X helperMethod() { doSomethingUsingWhatsInjected(aaa); }
}
The issue is that when I bind IFoo to Foo like this:
bind(IFoo.class).to(Foo.class).in(Singleton.class);
it appears like helperMethod() is being called before the aaa has been Injected since I'm seeing aaa as null. But if I instead don't use the class Helper and in-line all of its code directly in Foo, guice doesn't struggle.
What's the difference between these two approaches? Why is helperMethod() called before we know from where we're getting the implementation of IFoo? Can we use Helper along with injection?
Are you sure you're not calling helperMethod from within Helper's constructor? You omitted that part from the code you posted, but it would match the behavior you're seeing.
public class Test {
interface IFoo { }
static abstract class Helper implements IFoo {
Helper() { helperMethod(); }
abstract void helperMethod();
}
static class Foo extends Helper {
private final String aaa;
Foo(String aaa) { this.aaa = aaa; }
#Override
void helperMethod() { System.out.println(String.valueOf(aaa)); }
}
public static void main(String[] args) {
// Call helperMethod twice:
// once in the Helper.Helper(), once right here.
new Foo("expected").helperMethod();
// output:
// null
// expected
}
}
The first thing Foo does is implicitly call its superclass constructor, as if you typed super(); this necessarily happens as the very first statement in the subclass constructor. Consequently, this happens even before final variables like aaa are set, so your overridden method in Foo sees aaa as null. As in my example, this is not specific to Guice, but Guice injection can trigger the constructor just like anything else can.
This StackOverflow answer offers a more thorough discussion of this problem.

Categories