Let's imagine that we have to call one method from different classes by definition coming at run time. For example we receive JSON like this:
{"calculator": "MyClass1", "parameter1": 1.0, "parameter2": 2.0, ... }
MyClass1 and more classes either extend some base class or implement some interface (just to be able to enumerate them at run time). We have to create object, pass the parameters to the object and call calculate() method.
I can think of two ways to do this:
switch(calculatorString) { case "MyClass1": calculator = new MyClass1(); ...
using Java Reflection
The first way is really stupid because the code must be updated each time new calculator class is added to the project. The second way is slightly better, but the IDE is unable to catch any type errors we make while creating the objects and invoking the method.
Are there other ways to do this (possibly better)?
You could maybe use the Java Service Provider Interface:
See for example here:
https://docs.oracle.com/javase/tutorial/sound/SPI-intro.html
https://www.baeldung.com/java-spi
It allows for different implementations/services that you implement (you still need class names in the services files) but don't have to use reflection directly.
You define the service providers in the META-INF
META-INF/services/com.baeldung.rate.spi.ExchangeRateProvider
Your services can register themselves and if you allow them to use the input json, you will be very flexible.
Reflection is the best way to create object at runtime, but its all depend on usecase.
You can also use factory design pattern for object Creation.
Using ReflectionAPI
try {
cls = Class.forName(className);
instance = cls.newInstance();
instance = BeanUtils.populateBean(properties, cls);
} catch (Exception e) {
e.printStackTrace();
}
BeanUtil Class
public static Object populateBean(Map<String, Object> propertyMap, Class<?> clazz) throws Exception {
PropertyUtilsBean bean = new PropertyUtilsBean();
Object obj = null;
try {
obj = clazz.newInstance();
for(Map.Entry<String, Object> entrySet: propertyMap.entrySet()) {
PropertyDescriptor descriptor = null;
try {
descriptor =
bean.getPropertyDescriptor(obj, entrySet.getKey());
if (descriptor == null) {
continue;
}
Method writeMethod = bean.getWriteMethod(descriptor);
writeMethod.invoke(obj, convert(descriptor.getPropertyType(), entrySet.getValue(), DATE_PATTERN));
} catch (IncompatibleConversion e) {
throw e;
} catch (Exception e) {
throw new Exception("Unable to parse");
}
}
}catch(Exception e) {
throw e;
}
return obj;
}
Convert Class
private static Object convert(Class<?> clzz, Object value, String datePattern) throws Exception {
if (clzz.isAssignableFrom(BigInteger.class)) {
if (value == null) {
return value;
}
if (value instanceof BigInteger) {
return value;
}
try {
return new BigInteger(value.toString());
} catch (Exception e) {
throw new IncompatibleConversion(e);
}
} else if (clzz.isAssignableFrom(BigDecimal.class)) {
if (value == null) {
return value;
}
if (value instanceof BigDecimal) {
return parseBigDecimal(value.toString(), DECIMAL_PRECISION);
}
try {
return parseBigDecimal(value.toString(), DECIMAL_PRECISION);
} catch (Exception e) {
throw new IncompatibleConversion(e);
}
} else if (clzz.isAssignableFrom(Integer.class)) {
if (value == null) {
return value;
}
if (value instanceof Integer) {
return value;
}
try {
return new Integer(value.toString());
} catch (Exception e) {
throw new IncompatibleConversion(e);
}
} else if (clzz.isAssignableFrom(Long.class)) {
if (value == null) {
return value;
}
if (value instanceof Long) {
return value;
}
try {
return new Long(value.toString());
} catch (Exception e) {
throw new IncompatibleConversion(e);
}
} else if (clzz.isAssignableFrom(String.class)) {
if (value == null) {
return value;
}
if (value instanceof String) {
return value;
}
try {
return value.toString();
} catch (Exception e) {
throw new IncompatibleConversion(e);
}
} else if (clzz.isAssignableFrom(Date.class)) {
if (value == null) {
return value;
}
if (value instanceof Date) {
return value;
}
if (datePattern == null) {
throw new Exception("date pattern cannot be null");
}
try {
SimpleDateFormat sdf = new SimpleDateFormat(datePattern);
return sdf.parse(value.toString());
} catch (Exception e) {
throw new IncompatibleConversion(e);
}
} else if (clzz.isAssignableFrom(Byte.class)) {
if (value == null) {
return value;
}
if (value instanceof Byte) {
return (value);
} else if (value instanceof Number) {
return new Byte(((Number) value).byteValue());
}
try {
return (new Byte(value.toString()));
} catch (Exception e) {
throw new IncompatibleConversion(e);
}
} else if (clzz.isAssignableFrom(Float.class)) {
if (value == null) {
return value;
}
if (value instanceof Float) {
return (value);
}
try {
return new Float(value.toString());
} catch (Exception e) {
throw new IncompatibleConversion(e);
}
} else if (clzz.isAssignableFrom(Double.class)) {
if (value == null) {
return value;
}
if (value instanceof Double) {
return (value);
}
try {
return new Double(value.toString());
} catch (Exception e) {
throw new IncompatibleConversion(e);
}
}
throw new Exception("Incompactible Conversion");
}
Related
I am trying to call one method 12 times asynchronously. But before the call I am setting something different for each method call. How can I do this in a more elegant way.
I am using spring as well.
I am aware of #async but how can I change the body 12 times ?
Callable<Object> task4 = () -> {
CallContextHolder.setContext(callContext);
try {
Object m = dbQuery(userId);
if (m == null){
throw new RuntimeException();
}
return m;
}
catch (Exception e) {
throw new IllegalStateException("task interrupted", e);
}
};
Callable<Object> task5 = () -> {
CallContextHolder.setContext(callContext); //here is the difference in every task
try {
Object m = dbQuery(userId);
if (m == null){
throw new RuntimeException();
}
return m;
}
catch (Exception e) {
throw new IllegalStateException("task interrupted", e);
}
You can use something like the following method
public Callable<Object> getCallable(CallContext context, String userId) { //replace types fro parameters to appropriate
return () -> {
CallContextHolder.setContext(callContext);
try {
Object m = dbQuery(userId);
if (m == null){
throw new RuntimeException();
}
return m;
}
catch (Exception e) {
throw new IllegalStateException("task interrupted", e);
}
};
}
And use it like this
Callable<Object> call1 = getCallable(callContext, userId);
Callable<Object> call2 = getCallable(callContext, userId);
You can try to use some type of loop to generate those callables and store them in a list.
Spring has made it so incredibly easy to set up application properties...but how would you do it without Spring?
I need to deploy a Java / Groovy application to a server where using Spring is out of the question... and I also don't have the liberty to install anything like Redis either. One option I am considering is to set up a Spring Cloud Config Server elsewhere and have my application consume properties from the config server. Trouble is, that is a bit of an overkill for my project now.
Could anyone suggest a way to do this in good, old, plain Java? :)
This is a really simple and basic example, but you can modify it as you like:
PropertyConfigurator.java
public class PropertiesConfigurator
{
Properties properties = new Properties();
String configInputPath = null;
InputStream configInputStream = null;
public PropertiesConfigurator(String configInputPath)
{
this.configInputPath = configInputPath;
}
public PropertiesConfigurator load() throws IOException, PropertyException
{
try
{
this.configInputStream = new FileInputStream(this.configInputPath);
// load a properties file
this.properties.load(this.configInputStream);
validate();
}
catch (IOException ex)
{
System.out.println("Failed load properties file: " + this.configInputPath);
throw ex;
}
catch (PropertyException ex)
{
System.out.println("One or more properties are empty");
throw ex;
}
finally
{
if (this.configInputStream != null)
{
try
{
this.configInputStream.close();
}
catch (IOException ex)
{
System.out.println("Failed to close input stream");
throw ex;
}
}
}
return this;
}
private void validate() throws PropertyException
{
Enumeration<?> e = this.properties.propertyNames();
while (e.hasMoreElements())
{
String key = (String) e.nextElement();
String value = this.properties.getProperty(key);
if (value.isEmpty())
{
System.out.println(String.format("Property %s is empty!", key));
throw new PropertyException("One or more properties are empty");
}
}
}
public String getProperty(String key)
{
return this.properties.getProperty(key);
}
#Override
public boolean equals(Object o)
{
if (this == o)
return true;
if (!(o instanceof PropertiesConfigurator))
return false;
PropertiesConfigurator that = (PropertiesConfigurator) o;
if (properties != null ? !properties.equals(that.properties) : that.properties != null)
return false;
if (configInputPath != null ? !configInputPath.equals(that.configInputPath) : that.configInputPath != null)
return false;
return configInputStream != null ?
configInputStream.equals(that.configInputStream) :
that.configInputStream == null;
}
#Override
public int hashCode()
{
int result = properties != null ? properties.hashCode() : 0;
result = 31 * result + (configInputPath != null ? configInputPath.hashCode() : 0);
result = 31 * result + (configInputStream != null ? configInputStream.hashCode() : 0);
return result;
}
}
PropertyException.java
public class PropertyException extends Exception
{
public PropertyException()
{
}
public PropertyException(String message)
{
super(message);
}
public PropertyException(String message, Throwable throwable)
{
super(message, throwable);
}
}
MainRunner.java
public class MainRunner
{
public static void main(String[] args)
{
try
{
String configFilePath = "application.properties";
PropertiesConfigurator propertiesConfigurator = new PropertiesConfigurator(configFilePath).load();
String prop1 = propertiesConfigurator.getProperty("keyprop1");
// Do whatever you want with prop1
// ...
}
catch (PropertyException ex)
{
System.out.println("Failed to load properties");
System.exit(1);
}
catch (Exception ex)
{
System.out.println("Error in main application");
System.exit(1);
}
}
}
Example of application.properties
keyprop1=value1
keyprop2=value2
Again, it's very basic and you should definitely improve this code and add your logic, validation, etc.
Take a look at http://constretto.org. That's easy to use configuration framework.
I have class test it contains other complex object private class2 e; and that object contains other complex object private class3 b;
public class class3 {
private String x;
private String y;
public String getX() {
return x;
}
public void setX(String x) {
this.x = x;
}
public String getY() {
return y;
}
public void setY(String y) {
this.y = y;
}
}
//class2
public class class2 {
private String n;
private class3 b;
public String getN() {
return n;
}
public void setN(String n) {
this.n = n;
}
public class3 getB() {
return b;
}
public void setB(class3 b) {
this.b = b;
}
}
//class test
public class test {
private String w;
private class2 e;
public String getW() {
return w;
}
public void setW(String w) {
this.w = w;
}
public class2 getE() {
return e;
}
public void setE(class2 e) {
this.e = e;
}
}
What i need to accomplish is having an Object from test i want to call all getters and if it returns complex object object from other class i want to to go recursively till no complex objects left
i could read all test object data , the part i'm missing is the recessive part
Here is my code :-
private static void writeInLogger(Object obj, String str) {
Class klazz = obj.getClass();
if (klazz.isPrimitive() || obj instanceof String
|| obj instanceof Integer || obj instanceof Double
|| obj instanceof Boolean)
System.out.println(str + obj.toString());
else {
try {
for (PropertyDescriptor propertyDescriptor : Introspector
.getBeanInfo(klazz).getPropertyDescriptors()) {
Method m = propertyDescriptor.getReadMethod();
if (m != null){
Object object = m.invoke(obj);
Class klazz2 = object.getClass();
if(klazz2.isPrimitive() || object instanceof String|| object instanceof Integer || object instanceof Double|| object instanceof Boolean){
System.out.println(m + str + m.invoke(obj).toString());
}
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IntrospectionException e) {
e.printStackTrace();
}
}
}
Updated your writeInLogger method. I also added to check for the write method, else you get Class also as a property and the stack blows.
private static void writeInLogger(Object obj, String str) {
Class klazz = obj.getClass();
if (klazz.isPrimitive() || obj instanceof String || obj instanceof Integer || obj instanceof Double
|| obj instanceof Boolean)
System.out.println(str + obj.toString());
else {
try {
for (PropertyDescriptor propertyDescriptor : Introspector.getBeanInfo(klazz).getPropertyDescriptors()) {
if(propertyDescriptor.getWriteMethod() == null)
continue;
Method m = propertyDescriptor.getReadMethod();
if (m != null) {
Object object = m.invoke(obj);
if(object != null)
writeInLogger(object, str);
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IntrospectionException e) {
e.printStackTrace();
}
}
}
private static void writeInLogger(Object obj, String str) {
if (obj == null) {
System.out.println(str + "null");
return;
}
Class klazz = obj.getClass();
if (klazz.isPrimitive() || obj instanceof String
|| obj instanceof Integer || obj instanceof Double
|| obj instanceof Boolean)
System.out.println(str + obj.toString());
else {
try {
for (Field field : klazz.getDeclaredFields()) {
field.setAccessible(true);
Object f = field.get(obj);
field.setAccessible(false);
writeInLogger(f, str);
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IntrospectionException e) {
e.printStackTrace();
}
}
}
Browse all fields in class and get the value object as the writeInLogger parameter.
getFields() only get public fields, getDeclaredFields to get all fields in class.
I'm trying to read a serialized Java file containing instances of classes I don't have in my classpath while reading.
Is there a way (perhaps by writing my own ObjectInputStream?) to ignore those ClassNotFoundException and replace the corresponding object of the stream by null ?
The object I want to read is similar to this one :
public class Log {
private String someField;
private Throwable throwable;
}
Actually, that Log object is read, but I don't have in my classpath the concrete class of some Log.throwable values. I would want that in that case, the throwable field value would be null but I want my Log object with the other fields read.
If I catch the exception, I couldn't even have my Log object.
Actually, I have tried multiple way to do this (extend ObjectInputStream and implement ObjectInputStream.readClassDescriptor() in order to return a Proxy of an ObjectStreamClass which would return null for default method ObjectStreamClass.getResolveException(), using Javassist because JDK cannot proxify classes, but the problem is : ObjectStreamClass cannot be instantiated outside of java.io package).
But I finally found a (rather ugly) way to do this :
public class DecompressibleObjectInputStream extends ObjectInputStream {
private static Logger logger = LoggerFactory.getLogger(DecompressibleObjectInputStream.class);
public DecompressibleObjectInputStream(InputStream in) throws IOException {
super(in);
try {
// activating override on readObject thanks to https://stackoverflow.com/a/3301720/535203
Field enableOverrideField = ObjectInputStream.class.getDeclaredField("enableOverride");
enableOverrideField.setAccessible(true);
Field fieldModifiersField = Field.class.getDeclaredField("modifiers");
fieldModifiersField.setAccessible(true);
fieldModifiersField.setInt(enableOverrideField, enableOverrideField.getModifiers() & ~Modifier.FINAL);
enableOverrideField.set(this, true);
} catch (NoSuchFieldException e) {
warnCantOverride(e);
} catch (SecurityException e) {
warnCantOverride(e);
} catch (IllegalArgumentException e) {
warnCantOverride(e);
} catch (IllegalAccessException e) {
warnCantOverride(e);
}
}
private void warnCantOverride(Exception e) {
logger.warn("Couldn't enable readObject override, won't be able to avoid ClassNotFoundException while reading InputStream", e);
}
#Override
public void defaultReadObject() throws IOException, ClassNotFoundException {
try {
super.defaultReadObject();
} catch (ClassNotFoundException e) {
logger.warn("Potentially Fatal Deserialization Operation.", e);
}
}
#Override
protected Object readObjectOverride() throws IOException, ClassNotFoundException {
// copy of JDK 7 code avoiding the ClassNotFoundException to be thrown :
/*
// if nested read, passHandle contains handle of enclosing object
int outerHandle = passHandle;
try {
Object obj = readObject0(false);
handles.markDependency(outerHandle, passHandle);
ClassNotFoundException ex = handles.lookupException(passHandle);
if (ex != null) {
throw ex;
}
if (depth == 0) {
vlist.doCallbacks();
}
return obj;
} finally {
passHandle = outerHandle;
if (closed && depth == 0) {
clear();
}
}
*/
try {
int outerHandle = getObjectInputStreamFieldValue("passHandle");
int depth = getObjectInputStreamFieldValue("depth");
try {
Object obj = callObjectInputStreamMethod("readObject0", new Class<?>[] {boolean.class}, false);
Object handles = getObjectInputStreamFieldValue("handles");
Object passHandle = getObjectInputStreamFieldValue("passHandle");
callMethod(handles, "markDependency", new Class<?>[] {int.class, int.class}, outerHandle, passHandle);
ClassNotFoundException ex = callMethod(handles, "lookupException", new Class<?>[] {int.class}, passHandle);
if (ex != null) {
logger.warn("Avoiding exception", ex);
}
if (depth == 0) {
callMethod(getObjectInputStreamFieldValue("vlist"), "doCallbacks", new Class<?>[] {});
}
return obj;
} finally {
getObjectInputStreamField("passHandle").setInt(this, outerHandle);
boolean closed = getObjectInputStreamFieldValue("closed");
if (closed && depth == 0) {
callObjectInputStreamMethod("clear", new Class<?>[] {});
}
}
} catch (NoSuchFieldException e) {
throw createCantMimicReadObject(e);
} catch (SecurityException e) {
throw createCantMimicReadObject(e);
} catch (IllegalArgumentException e) {
throw createCantMimicReadObject(e);
} catch (IllegalAccessException e) {
throw createCantMimicReadObject(e);
} catch (InvocationTargetException e) {
throw createCantMimicReadObject(e);
} catch (NoSuchMethodException e) {
throw createCantMimicReadObject(e);
} catch (Throwable t) {
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
}
if (t instanceof IOException) {
throw (IOException)t;
}
throw createCantMimicReadObject(t);
}
}
private IllegalStateException createCantMimicReadObject(Throwable t) {
return new IllegalStateException("Can't mimic JDK readObject method", t);
}
#SuppressWarnings("unchecked")
private <T> T getObjectInputStreamFieldValue(String fieldName) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
Field declaredField = getObjectInputStreamField(fieldName);
return (T) declaredField.get(this);
}
private Field getObjectInputStreamField(String fieldName) throws NoSuchFieldException {
Field declaredField = ObjectInputStream.class.getDeclaredField(fieldName);
declaredField.setAccessible(true);
return declaredField;
}
#SuppressWarnings("unchecked")
private <T> T callObjectInputStreamMethod(String methodName, Class<?>[] parameterTypes, Object... args) throws Throwable {
Method declaredMethod = ObjectInputStream.class.getDeclaredMethod(methodName, parameterTypes);
declaredMethod.setAccessible(true);
try {
return (T) declaredMethod.invoke(this, args);
} catch (InvocationTargetException e) {
throw e.getCause();
}
}
#SuppressWarnings("unchecked")
private <T> T callMethod(Object object, String methodName, Class<?>[] parameterTypes, Object... args) throws Throwable {
Method declaredMethod = object.getClass().getDeclaredMethod(methodName, parameterTypes);
declaredMethod.setAccessible(true);
try {
return (T) declaredMethod.invoke(object, args);
} catch (InvocationTargetException e) {
throw e.getCause();
}
}
}
Then I overrode the ObjectInputStream.readClassDescriptor() in order to ignore differences between serialVersionUID also (as described in that answer) and I've got an ObjectInputStream which can read nearly everything !
I don't think there is a way to do this ... apart from cloning and modifying the Java serialization implementation.
Certainly, readObject and readResolve hooks won't help, because they rely on methods of the class that you cannot load.
I'm a Java (Android) beginner (coming from Python) and I'm trying to catch an exception using Try-Catch as follows:
try {
u.save();
} catch (Exception e) {
Log.wtf("DO THIS", " WHEN SAVE() FAILS");
}
To my surprise I don't see my Log message but I still get the following error:
09-25 10:53:32.147: E/SQLiteDatabase(7991):
android.database.sqlite.SQLiteConstraintException: error code 19:
constraint failed
Why doesn't it catch the Exception? Am I doing something wrong here? All tips are welcome!
The save() method looks as follows:
public final void save() {
final SQLiteDatabase db = Cache.openDatabase();
final ContentValues values = new ContentValues();
for (Field field : mTableInfo.getFields()) {
final String fieldName = mTableInfo.getColumnName(field);
Class<?> fieldType = field.getType();
field.setAccessible(true);
try {
Object value = field.get(this);
if (value != null) {
final TypeSerializer typeSerializer = Cache.getParserForType(fieldType);
if (typeSerializer != null) {
// serialize data
value = typeSerializer.serialize(value);
// set new object type
if (value != null) {
fieldType = value.getClass();
// check that the serializer returned what it promised
if (!fieldType.equals(typeSerializer.getSerializedType())) {
Log.w(String.format("TypeSerializer returned wrong type: expected a %s but got a %s",
typeSerializer.getSerializedType(), fieldType));
}
}
}
}
// TODO: Find a smarter way to do this? This if block is necessary because we
// can't know the type until runtime.
if (value == null) {
values.putNull(fieldName);
}
else if (fieldType.equals(Byte.class) || fieldType.equals(byte.class)) {
values.put(fieldName, (Byte) value);
}
else if (fieldType.equals(Short.class) || fieldType.equals(short.class)) {
values.put(fieldName, (Short) value);
}
else if (fieldType.equals(Integer.class) || fieldType.equals(int.class)) {
values.put(fieldName, (Integer) value);
}
else if (fieldType.equals(Long.class) || fieldType.equals(long.class)) {
values.put(fieldName, (Long) value);
}
else if (fieldType.equals(Float.class) || fieldType.equals(float.class)) {
values.put(fieldName, (Float) value);
}
else if (fieldType.equals(Double.class) || fieldType.equals(double.class)) {
values.put(fieldName, (Double) value);
}
else if (fieldType.equals(Boolean.class) || fieldType.equals(boolean.class)) {
values.put(fieldName, (Boolean) value);
}
else if (fieldType.equals(Character.class) || fieldType.equals(char.class)) {
values.put(fieldName, value.toString());
}
else if (fieldType.equals(String.class)) {
values.put(fieldName, value.toString());
}
else if (fieldType.equals(Byte[].class) || fieldType.equals(byte[].class)) {
values.put(fieldName, (byte[]) value);
}
else if (ReflectionUtils.isModel(fieldType)) {
values.put(fieldName, ((Model) value).getId());
}
else if (ReflectionUtils.isSubclassOf(fieldType, Enum.class)) {
values.put(fieldName, ((Enum<?>) value).name());
}
}
catch (IllegalArgumentException e) {
Log.e(e.getClass().getName(), e);
}
catch (IllegalAccessException e) {
Log.e(e.getClass().getName(), e);
}
}
if (mId == null) {
mId = db.insert(mTableInfo.getTableName(), null, values);
}
else {
db.update(mTableInfo.getTableName(), values, "Id=" + mId, null);
}
Cache.getContext().getContentResolver()
.notifyChange(ContentProvider.createUri(mTableInfo.getType(), mId), null);
}
There are two classes to catch the problems.
Error
Exception
Both are sub-class of Throwable class. When there is situation we do not know, that particular code block will throw Exception or Error? You can use Throwable. Throwable will catch both Errors & Exceptions.
Do this way
try {
u.save();
} catch (Throwable e) {
e.printStackTrace();
}
Constraint failed usually indicates that you did something like pass a null value into a column that you declare as not null when you create your table.
do this way
try {
// do some thing which you want in try block
} catch (JSONException e) {
e.printStackTrace();
Log.e("Catch block", Log.getStackTraceString(e));
}
Try
try {
u.save();
} catch (SQLException sqle) {
Log.wtf("DO THIS", " WHEN SAVE() FAILS");
}catch (Exception e) {
Log.wtf("DO THIS", " WHEN SAVE() FAILS");
}
Log is expecting certain variable-names like verbose(v), debug(d) or info(i).
Your "wtf" doesnt belong there. Check this answer for more info -->
https://stackoverflow.com/a/10006054/2074990
or this:
http://developer.android.com/tools/debugging/debugging-log.html