I have a Java program that calls an external API (RealApi in the code below) and sometimes I want to avoid calling this API and instead return pre-constructed responses (generated by FakeApi).
So, I ended up duplicating this kind of construct in most of my methods:
public Type1 m1(String s) {
try {
Type1 r = FakeApi.m1(s);
if (r != null) {
return r;
}
} catch (Exception e) {
// log error
}
return RealApi.m1(s);
}
What are some options to avoid duplicating this try/catch block everywhere? It's important that if FakeApi throws an exception or returns null, the RealApi must be called.
One option would be encapsulate the error checking behaviour into its own method:
public <T> T fakeOrReal(Supplier<T> fake, Supplier<T> real) {
try {
T r = fake.get();
if (r != null) {
return r;
}
}
catch (Exception e) {
// log error
}
return real.get();
}
You can then just call it with
public Type1 m1(String s) {
return fakeOrReal(() -> FakeApi.m1(s), () -> RealApi.m1(s));
}
This is not as simple as Thomas Preißler's answer but it will help you not repeat any method at all. So if you expand the interface, you have to modify only the concrete classes and not the linker which describes the actual behavior you want.
Create an interface that contains all the methods of RealApi:
interface Api {
Type1 m1(String s);
}
Then a class that does the actual call:
class ConcreteApi implements Api {
public Type1 m1(String s) {
return RealApi.m1(s);
}
}
Then create your FakeApi:
class TotallyFakeApi implements Api {
public Type1 m1(String s) {
return FakeApi.m1(s);
}
}
Now, the tricky part to avoid repeating yourself:
private static Object callImplementation(Api api, Method method, Object[] methodArgs) throws Exception {
Method actualMethod = api.getClass().getMethod(actualMethod.getName(), actualMethod.getParameterTypes());
return actualMethod.invoke(api, methodArgs);
}
Api fakeOrReal(Api fakeApi, Api realApi) {
return (Api) Proxy.newProxyInstance(
FakeApi.class.getClassLoader(),
new Class[]{Api.class},
(proxy, method, methodArgs) -> {
try {
Object r = callImplementation(fakeApi, method, methodArgs);
if (r != null) {
return r;
}
} catch (Exception e) {
// logError(e);
}
return callImplementation(realApi, method, methodArgs);
}
);
}
Get the actual implementation like this:
Api apiToUse = fakeOrReal(new TotallyFakeApi(), new ConcreteApi());
Related
I want to reduce the validations, maybe using some methods.
I'm delaing with a basic crud, and on the update endpoint, they want to update just one field at once, and giving me a arbitrary number of params, can be 1,2 or 10. and they dont want of course to erase the database if a parameter isnt sent.
#PostMapping("/updateTask")
#ResponseBody
public String updateTask(#RequestBody Task sentTask) {
Task dbTask = null;
try {
dbTask = taskDao.findByIdTask(sentTask.getIdTask());
if(isValid(sentTask.getAuthor())){
dbTask.setAuthor(sentTask.getAuthor());
}
else{
dbTask.setAuthor(dbTask.getAuthor());
}
if(isValid(sentTask.getIdReport())){
dbTask.setIdReport(sentTask.getIdReport());
}
else{
dbTask.setIdReport(dbTask.getIdReport());
}
taskDao.save(dbTask);
} catch (Exception e) {
String response = "{\"data\":
{\"success\":\"false\",\"error\":\"Error updating the task:\"}}";
return response;
}
String response = "{\"data\":{\"success\":\"true\",\"message\":\"Task
updated successfully\",\"Id\":\"" + sentTask.getIdTask() + "\"}}\n";
return response;
}
public boolean isValid(Object data){
if (data == null){
return false;
}
if(data.equals("")){
return false;
}
return true;
}
I want some like this
public void setData(Object sentData, Object dbData){
if (isValid(sentData)){
dbData.setSentData
}
else{
dbData.setDbData
}
}
You can consider using Optional provided in java 8
Optional<String> authorOptional = Optional.ofNullable(sentTask.getAuthor());
if(authorOptional.isPresent()){
dbTask.setAuthor(sentTask.getAuthor());
}else{
dbTask.setAuthor(dbTask.getAuthor());
}
Optional<String> reportOptional = Optional.ofNullable(sentTask.getIdReport());
if(reportOptional.isPresent()){
dbTask.setIdReport(sentTask.getIdReport());
}else{
dbTask.setIdReport(dbTask.getIdReport());
}
OR
dbTask.setAuthor(Optional.ofNullable(sentTask.getAuthor()).isPresent()?sentTask.getAuthor():dbTask.getAuthor());
dbTask.setIdReport(Optional.ofNullable(sentTask.getIdReport()).isPresent()?sentTask.getIdReport():dbTask.getIdReport());
Now you don't need isValid or setData method
I would recommend business logic related changes should be handled service layer
1) First of all the code like this
else {
dbTask.setIdReport(dbTask.getIdReport());
}
doesn't make any sense as long as property value remains unchanged. So we could easily throw it away.
2) Some reduction could be achieved with following approach
Add following methods:
public void updateTask(Task received, Task existing) {
// run validations and copy only valid values
copyValid(received::getAuthor, existing::setAuthor);
copyValid(received::getReportId, existing::setReportId);
taskDao.save(existing);
}
private <T> void copyValid(Supplier<T> getter, Consumer<T> setter) {
Optional.ofNullable(getter.get())
.map(this::validOrNull)
.ifPresent(setter); // setter will be executed only for non-null values
}
private <T> T validOrNull(T data) {
if (data == null) {
return null;
}
if (data instanceof String && data.equals("")) {
return null; // if data is invalid return null
}
// additional checks for other types can be added here
return data; // otherwise return data as is
}
And adjust controller method like this
#PostMapping("/updateTask")
#ResponseBody
public String updateTask(#RequestBody Task sentTask) {
try {
Task dbTask = taskDao.findByIdTask(sentTask.getIdTask());
updateTask(sentTask, dbTask);
} catch (Exception e) {
// omitted
}
}
P.S. As already mentioned in another answer you should extract your business logic to separate service
This question is related to Issue in abstracting common code using function interface and Exception handling in Function interface. Getting idea from those I have written like below:
public void act(Input1 input) throws NonRetriableException, InvalidInputException {
Function<UpdateTaskInput, Boolean> func = item -> {
try {
activityManager.update(item);
return true;
} catch (InterruptedException | JSONException e) {
throw new NonRetriableException(e);
} catch (LockUnavailableException e) {
throw new NonRetriableException(e);
}
};
try {
lockManager.executeWithLock(input.getTaskID(), input, func);
} catch (LockUnavailableException e) {
log.error("{}",e);
throw new NonRetriableException(e);
}
}
and:
public void perform()
throws AutoAllocationException {
Function<UpdateTaskInput, Boolean> func = item -> {
try {
activityManager.allocateTask(item);
return true;
} catch (AutoAllocationException ex) {
log.error("{}",ex);
}
return false;
};
try {
lockManager.executeWithLock(input.getTaskID(), input, func);
} catch (LockUnavailableException e) {
log.error("{}",e);
}
}
executeWithLock() in LockManager is as follows:
#Override
public <T,R> R executeWithLock(String lockName, T input, Function<T,R> func) throws LockUnavailableException {
LockItem lockItem = acquireLock(lockName);
try {
R output = func.apply(input);
return output;
} finally {
releaseLock(lockItem);
}
}
Now the issue with the executeWithLock() function is, it always expects input as an argument, I cannot invoke this for any other function which does not have any input like doStuff().
But I would like to do it using Function interface only with something like following ( so you can see, T is omitted).
#Override
public <R> R executeWithLock(String lockName, Function<R> func) throws LockUnavailableException {
LockItem lockItem = acquireLock(lockName);
try {
R output = func.apply(input);
return output;
} finally {
releaseLock(lockItem);
}
}
Is there any way to do that with Function interface?
You could use a intermediate helper method, which accepts a Supplier<R> but no input. Which then creates a Function<?, R> and delegates to the other method:
public <R> R executeWithLock(String lockName, Supplier<R> supplier) throws LockUnavailableException{
return executeWithLock(
lockName,
null, // input is ignored by our function
ignored -> supplier.get() // this lambda will create Function<?, R> from the Supplier<R>
);
}
This could then be used like this:
executeWithLock("mylock", () -> "Some Value");
Whereas () -> "Some Value" is a Supplier<String>.
If you can't change that code, and thus not be able to add a intermediate helper method. You might just want to pass null as an argument, and then ignore it in the lambda:
executeWithLock("myLock", null, ignored -> doStuff());
You need two methods. The first should take a Supplier rather than a Function and the input. Using Supplier is preferable because it gives you the flexibility to use zero or more input arguments. Using Function means you are limited to one.
You also need a second method which uses Runnable which supports zero or more input arguments and a void return:
public static <R> R executeWithLock(String lockName, Supplier<R> func) {
Lock lockItem = acquireLock(lockName);
try {
return func.get();
} finally {
releaseLock(lockItem);
}
}
public static void executeWithLock(String lockName, Runnable func) {
Lock lockItem = acquireLock(lockName);
try {
func.run();
} finally {
releaseLock(lockItem);
}
}
Sample usage for these example methods:
private static String foo(String input) { return input; }
private static void bar(String input) { }
would look like:
String ret = executeWithLock("lockName", () -> foo("someInput"));
executeWithLock("lockName", () -> bar("someInput")); // void return
Java is able to infer which version of executeWithLock is required based on whether or not there's a return type. If you wanted to be explicit, you could give the methods different names.
Say I have the following code...
#FunctionalInterface
static interface MessageFunction<T> {
void send(T obj);
}
static #interface Message {
Class<?> value();
}
static class Foo {
#Message(String.class)
MessageFunction<String> bass = (string) -> {
// Do Stuff
};
}
static class MessageManager {
Map<Class<?>, MessageFunction<?>> messages = new HashMap<>();
public void register(Object obj) {
for (Field field : obj.getClass().getDeclaredFields()) {
Message message = field.getAnnotation(Message.class);
if (message != null) {
MessageFunction<?> function;
try {
function = (MessageFunction<?>) field.get(obj);
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
return;
}
Method sendMethod;
try {
// Will this work?
sendMethod = function.getClass().getDeclaredMethod("send", Object.class);
} catch (NoSuchMethodException | SecurityException e) {
e.printStackTrace();
return;
}
// How do I do something like this?
/*if (sendMethod.testParamaters(message.value())) {
this.messages.put(message.value(), function);
}*/
}
}
}
}
public static void main(String[] args) {
MessageManager manager = new MessageManager();
manager.register(new Foo());
}
I am reflecting a field that references an #FunctionalInterface of a generic type. Because the method parameter is also generic I have no way of knowing what parameters it accepts, Thus I must pass it along through other means (the annotation).
The issue is that there is the annotation value and the generic type do not have to match and there seems to be no way to check. I wan't it to fail in registration if the type listed in the annotation would not be accepted into the send method.
How would I go about thing this without actually calling the method. Is there a way? Better yet although I know its most likely impossible, is there a way to know what the parameter type is without the annotation?
The following is just a suggestion, I have used it in my project. But it is not a perfect solution for the question. May be you can download the source of GenericHibernateDao framework and see the sourcecode of method "getTypeArguments". I think it is so cool!.
// get a class object for your entity
Class clazz = ...
Type type = clazz.getGenericSuperclass();
if (type instanceof ParameterizedType) {
Type trueType = ((ParameterizedType)type).getActualTypeArguments()[0];
Class modelClass = (Class) trueType;
// Now you can creat an Instance in you generic parameterType
Object entity = modelClass.forInstance();
}
I do something similar in some of my code Here is a snippet.
Method[] meths = actionClass.getMethods();
for (Method meth : meths) {
Class<?>[] pTypes = meth.getParameterTypes();
/*
* Filter out all methods that do not meet correct
* signature. The correct signature for an action method
* is: String actionName(HttpServletRequest request)
*/
//...check for the correct number of params and the correct param type
if (pTypes.length != 1 || !HttpServletRequest.class.toString().equals(pTypes[0].toString())) {
continue;
} else {
//...check for return type
if (!String.class.toString().equals(meth.getReturnType().toString())) {
continue;
}
}
//If you make it here than that means the method
//meets the requirements to be a full fledged action.
//...
}
I am trying to get method regardless of what parameters that method takes (as of now there is no method overloading and there wouldn't be in future). The only possible solution that i could come up with was
private Method getMethod(Class<?> clas, String methodName) {
try {
Method[] methods = clas.getMethods();
for (Method method : methods) {
if (method.getName().equalsIgnoreCase(methodName)) {
return method;
}
}
} catch (SecurityException e) {
e.printStackTrace();
}
return null;
}
What i want to ask that is there a way to fetch a method regardless of its parameters ? I was looking at clas.getMethod ("methodName", parameters) and if i provide null in there it will try to fetch a method which has no parameters. Which wouldn't be no case.
Any ideas ?
EDIT
Thanks guys for input. In my case, i know that there would be only one method regardless of its case. The reason i am using ignoreCase is because the input will be coming from a developer (in other team) and he will be providing the name as a hard-coded string. So to keep things from spilling out of our hands, I am using a safe approach.
No. The way you've done it is the way to go. A method is identified by its signature and the signature includes the name and the parameter types.
Here is a solution that retrieves all methods with the specified class and method name regardless of the method's parameters:
public class Test
{
private class Foo
{
public void bar()
{
}
public void bar(String s)
{
}
public void goo()
{
}
}
private static Method[] getMethods(Class<?> clazz, String methodName)
{
List<Method> methods = new ArrayList<Method>();
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method declaredMethod: declaredMethods)
{
if (declaredMethod.getName().equals(methodName))
{
methods.add(declaredMethod);
}
}
return methods.toArray(new Method[methods.size()]);
}
public static void main(String[] args)
{
Method[] methods = getMethods(Foo.class, "bar");
System.out.println(Arrays.toString(methods));
}
}
This generates the following output:
[public void com.example.Test$Foo.bar(java.lang.String), public void com.example.Test$Foo.bar()]
You've done just fine. This is basically the same as the solution to a similar problem I dealt with four years ago, creating a means to create callback methods in Java. The constructors for my Callback class were:
public Callback(Class<?> clazz, String methodName, Object parentObj) {
// Find a method with the matching name
Method[] allMethods;
try { allMethods = clazz.getMethods(); }
catch(SecurityException se) { allMethods = new Method[0]; }
int count = 0;
Method single = null;
for(Method m : allMethods) {
if(m.getName().equals(methodName)) {
single = m;
count++;
}
// Can't have more than one instance
if(count > 1)
throw new IllegalArgumentException(clazz.getName()
+ " has more than one method named " + methodName);
}
if(count == 0) // No instances found
throw new IllegalArgumentException(clazz.getName()
+ " has no method named " + methodName);
this.parentObj = parentObj;
this.method = single;
this.parameters = single.getParameterTypes();
}
public Callback(
Class<?> clazz,
String methodName,
Object parentObj,
Class<?>...parameters)
{
try { this.method = clazz.getMethod(methodName, parameters); }
catch(NoSuchMethodException nsme) { nsme.printStackTrace(); }
catch(SecurityException se) { se.printStackTrace(); }
this.parentObj = parentObj;
this.parameters = parameters;
}
My Callback class isn't really useful any more in the era of Java 8, but at the time the only real means for a "callback" in java was anonymous interface implementations, which wasn't sufficient for my use-case.
As you can see in the first constructor, it throws an exception if it finds multiple methods with the same name.
Using java streams there is a really short method of finding a method, the first match, by its name only:
Stream.of(type.getMethods())
.filter((m) -> m.getName().equals(searchedName))
.findFirst()
.get();
I think this is a short and readable possibility in this case.
I'm attempting to make a system similar to https://github.com/ElgarL/TownyChat/blob/master/src/com/palmergames/bukkit/TownyChat/TownyChatFormatter.java
replacer.registerFormatReplacement(Pattern.quote("{worldname}"), new TownyChatReplacerCallable() {
#Override
public String call(String match, LocalTownyChatEvent event) throws Exception {
return String.format(ChatSettings.getWorldTag(), event.getEvent().getPlayer().getWorld().getName());
}
});
replacer.registerFormatReplacement(Pattern.quote("{town}"), new TownyChatReplacerCallable() {
#Override
public String call(String match, LocalTownyChatEvent event) throws Exception {
return event.getResident().hasTown() ? event.getResident().getTown().getName() : "";
}
});
and more.
Is there a way to use annotations to cut down on the amount of repeated code, avoiding reflection to call the call method, and only using it during registration, if at all?
I'm not adverse to the idea of creating an annotation pre processor as I was already planning on doing this to enable automatically generating documentation.
Let's assume you write a small Annotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
#interface PatternHandler {
String value();
}
And create a class like
class Callables {
#PatternHandler("foo")
public static final TownyChatReplacerCallable FOO = new TownyChatReplacerCallable() {
#Override
public String call(String match, String event) {
return "This is foo handler called with " + match + "," + event;
}
};
#PatternHandler("bar")
public static final TownyChatReplacerCallable BAR = new TownyChatReplacerCallable() {
#Override
public String call(String match, String event) {
return "This is foo handler called with " + match + "," + event;
}
};
}
Now you can take the whole class or even multiple classes that contain those static fields and pass it to some registry method that iterates reflectively over each field in that class and if it's an annotated callable registers that.
class AnnotationRegistry {
public static void register(String pattern, TownyChatReplacerCallable handler) {}
public static void register(Class<?> clazz) {
// only fields declared by this class, not inherited ones (static fields can't be inherited)
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
// must have that annotation
PatternHandler annotation = field.getAnnotation(PatternHandler.class);
if (annotation != null) {
// must be static
if (!Modifier.isStatic(field.getModifiers())) {
System.out.println("Field must be static:" + field.getName());
continue;
}
// get content of that field
try {
Object object = field.get(null);
// must be != null and a callable
if (object instanceof TownyChatReplacerCallable) {
register(annotation.value(), (TownyChatReplacerCallable) object);
} else {
System.out.println("Field must be instanceof TownyChatReplacerCallable:" + field.getName());
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
That would save you a bit code and would have no speed disadvantage at runtime since there is no need to use reflection to call those callables.
Full example here: http://ideone.com/m3PPcY
Besides using static fields, you can also use non static ones if you pass an instance of a class to the registry which would then be used like Object object = field.get(instance); instead of the null.
Furthermore, instead of fields the same approach would work with methods which would be less code to write:
#PatternHandler("foo")
public static String fooMethod(String match, String event) {
return "This is foo handler called with " + match + "," + event;
}
Registry would then look for all Methods. Then for example wrap them in
class MethodAdapter implements TownyChatReplacerCallable {
private final Method method;
public MethodAdapter(Method m) {
method = m;
}
#Override
public String call(String match, String event) {
try {
return (String) method.invoke(null, match, event);
} catch (Exception e) {
e.printStackTrace();
return "OMGZ";
}
}
}
and continue as usual. But beware: invoking a method reflectively is potentially slower than calling it directly via code - few percent only, nothing to worry about
Full example for methods: http://ideone.com/lMJsrl
You can try new Java 8 Lambda Expressions instead (http://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html).
replacer.registerFormatReplacement(Pattern.quote("{worldname}"), new TownyChatReplacerCallable() {
#Override
public String call(String match, LocalTownyChatEvent event) throws Exception {
return String.format(ChatSettings.getWorldTag(), event.getEvent().getPlayer().getWorld().getName());
}
});
Can be written as :
replacer.registerFormatReplacement(
Pattern.quote("{worldname}"),
(match, event) -> { return String.format(ChatSettings.getWorldTag(), event.getEvent().getPlayer().getWorld().getName()); }
});
You can also push it further with another interface, method, ... that wrap it