Java - Reflection - Convert to JSON Array - java

i create and set values like the following in java
public Class creatObjectWithDefaultValue(String className) throws IllegalArgumentException, IllegalAccessException {
DefaultParamValues defaultParamValues = null;
Class objectClass = null;
try {
objectClass = Class.forName(className);
Field[] fields = objectClass.getClass().getDeclaredFields();
for(Field f:fields){
if(!f.isAccessible()){
f.setAccessible(true);
Class<?> type = f.getType();
if(type.equals(Integer.class)){
f.set(objectClass, defaultParamValues.INTEGER);
} else if(type.equals(BigInteger.class)){
f.set(objectClass, defaultParamValues.BIGINTEGER);
}else if(type.equals(LocalDate.class)){
f.set(objectClass, defaultParamValues.DATE);
}else if(type.equals(Boolean.class)){
f.set(objectClass, defaultParamValues.BOOLEAN);
}else if(type.equals(Long.class)){
f.set(objectClass, defaultParamValues.LONGVALUE);
}
f.setAccessible(false);
}
//System.out.println(f.get(objectClass));
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return objectClass;
}
now i want to convert the return object as JSON or JSON Array i tried some thing like this but it throws exception as The constructor JSONObject(Class) is undefined
System.out.println ( new JSONObject( te.creatObjectWithDefaultValue("com.hexgen.ro.request.CreateRequisitionRO") ).toString () );
Please help me to correct the mistake.
Best Regards

Why don't you use a Jackson for working with JSON data? Reinventing the wheel is most often error-prone and is only suitable for either education or the case when no library or framework fits your purposes at all.
Now, for JSON <-> Object conversion, there is not a single reason not to use a higher level framework, unless you're explicitly trying to investigate Reflection itself.

there is no constructor with the parameter class in JSONObject.
but you could create an object of the class and pass it to the jsonobject constructor:
System.out.println ( new JSONObject(te.creatObjectWithDefaultValue("com.hexgen.ro.request.CreateRequisitionRO").newInstance() ).toString () );
this only works with classes that have a parameterless constructor

This is very clear.
The constructor JSONObject(Class) is undefined
The API → http://www.json.org/javadoc/org/json/JSONObject.html

Related

Stream through methods to find Rest mapping information

I have a simple, but incredibly ugly looking method.
The issue I am having is that I feel this can be done a million times more elegantly. In addition, I would also like to scan a method for more than one annotation, and not just the Rest endpoint declarations.
I feel this can be done through a stream of Annotations[] (method.getDeclaredAnnotations()) and filtered by a List<Annotation> restEndpointAnnotationsAndOtherAnnotations, but I cannot seem to get it to work.
Any help would be greatly appreciated. I think it's probably a fairly fun challenge for some people. The primary issue I am getting (I think) is trying to convert Class<? extends Annotation> to Annotation, but perhaps I am missing the mark.
public RestEndpoint mapToRestEndpoint(Method method) {
String url = null;
if (method.isAnnotationPresent(GetMapping.class)) {
url = method.getAnnotation(GetMapping.class).value()[0];
} else
if (method.isAnnotationPresent(PutMapping.class)) {
url = method.getAnnotation(PutMapping.class).value()[0];
} else
if (method.isAnnotationPresent(PostMapping.class)) {
url = method.getAnnotation(PostMapping.class).value()[0];
} else
if (method.isAnnotationPresent(PatchMapping.class)) {
url = method.getAnnotation(PatchMapping.class).value()[0];
} else
if (method.isAnnotationPresent(DeleteMapping.class)) {
url = method.getAnnotation(DeleteMapping.class).value()[0];
} else
if (method.isAnnotationPresent(RequestMapping.class)) {
url = method.getAnnotation(RequestMapping.class).value()[0];
} else return null;
return new RestEndpoint(url, true);
}
Where RestEndpoint is a simple POJO
#Value
public class RestEndpoint {
#NonNull String endpoint;
boolean isPublic;
}
I can actually find where it matches the Rest mapping using streams, but I cannot then apply the .value() method to it (since it doesn't know what annotation it is, and would be just as tedious to then cast to multiple annotation types)
EDIT:
This is a pretty handy way of getting the information on methods if anyone is interested.
ApplicationContext context = ((ContextRefreshedEvent) event).getApplicationContext();
context.getBean(RequestMappingHandlerMapping.class).getHandlerMethods();
Problem is in getAnnotation as it need concrete annotation class to know that it has somethings like value(). You can create helper method that try to invoke value() on given object and do other parsing.
private String getUrl(Method method, Class<? extends Annotation> annotationClass){
Annotation annotation = method.getAnnotation(annotationClass);
String[] value;
try {
value = (String[])annotationClass.getMethod("value").invoke(annotation);
} catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
return null;
}
return value[0];
}
Then use it like this:
String url = Stream.of(
GetMapping.class, PutMapping.class, PostMapping.class, PatchMapping.class, DeleteMapping.class, RequestMapping.class)
.filter(clazz -> method.isAnnotationPresent(clazz))
.map(clazz -> getUrl(method, clazz))
.findFirst().orElse(null);

Dynamically loading method from external class

I am trying to load methods Customer.cypher and Customer.cypherCBC method from my class Configuration. Customer class is rendering from different environments so few environmets are having cypherCBC() and cypher() method and few are having only cypher() method.
Now i want to check if cypherCBC if not there in Customer class then load cypher() method. My function is so far;
try {
Class<?> customerClass = Class.forName("com.myapp.impl.service.Customer");
Object obj = customerClass.newInstance();
//here getting "NoSuchMethodException" exception
Method methodCBC = customerClass.getDeclaredMethod("cypherCBC", String.class); //line - 7
if(methodCBC.getName().equals("cypherCBC")){
methodCBC.invoke(obj, new String(dbshPass));
System.out.println("CYPHER_CBC: "
+ methodCBC.invoke(obj, new String(dbshPass)));
}else{
Method method = customerClass.getDeclaredMethod("cypher", String.class);
method.invoke(obj, new String(dbshPass));
System.out.println("CYPHER: " + method.invoke(obj, new String(dbshPass)));
}
}catch (Exception e){
e.printStackTrace();
}
Getting an error at line 7.
NoSuchMethodException:
com.myapp.impl.service.Customer.cypherCBC(java.lang.String)
that means for particular environment class Customer doesn't having cypherCBC() method, but ideally it should come in else part and execute cypher() method.
Class<?> client = null;
Object obj = null;
try{
client = Class.forName("com.myapp.impl.service.Client");
obj = client.newInstance();
}catch (InstantiationException ex) {
System.err.println("Not able to create Instance of Class");
} catch (IllegalAccessException ex) {
System.err.println("Not able to access Class");
} catch (ClassNotFoundException ex) {
System.err.println("Not able to find Class");
}
try {
Method methodCBC = client.getDeclaredMethod("cypherCBC", String.class);
System.out.println("CYPHER_CBC: " + methodCBC.invoke(obj, new String(dbshPass)));
}catch (NoSuchMethodException ex) {
System.err.println("Not able to find Method on class");
ex.printStackTrace();
} catch (Exception e){
e.printStackTrace();
}
That is exactly what is to be expected: getDeclaredMethod() throws that exception when no method exists that meets your specification. And you are wondering that it throws an exception if the required method is missing? Hint: better read the javadoc next time. Don't assume that something does something, but verify your assumptions!
Besides: read your code again. What is it doing? You are asking "give me the method named 'foo'". And then, your next step is to ask that method "is your name 'foo'". So even without reading javadoc, it should become clear that your logic is flawed.
As solution, you can implement a non-throwing lookup yourself, like
private Method lookupCypher(Class<?> client, String methodName) {
for (Method declaredMethod : client.getDeclardMethods()) {
if (declaredMethod.getName().equals(methodName)) {
Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
if (parameterTypes.length == 1 && parameterTypes[0].equals(String.class)) {
// so declaredMethod has the given name, and takes one string as argument!
return declaredMethod;
}
}
// our search didn't reveal any matching method!
return null;
}
Using that helper method, you can rewrite your code to:
Method toInvoke = lookupCypher(client, "cypherCBC");
if (toInvoke == null) {
toInvoke = lookupCypher(client, "cypher");
}
toInvoke(obj, new String ...
Or, with the idea from hunter in mind; a much more "OO like" version:
interface CustomerCypherWrapper {
void cypher(String phrase);
}
class NewCustomerWrapper() implements CustomerCypherWrapper {
#Override
void cypher(String phrase) {
new Customer.cypherCBC(phrase);
}
}
class oldCustomerWrapper() implements CustomerCypherWrapper {
#Override
void cypher(String phrase) {
new Customer.cypher(phrase);
}
}
And your client code boils down to:
CustomerCypherWrapper wrapper =
(lookupCypher(..., "cypherCBC") == null)
? new NewCustomerWrapper()
: new OldCustomerWrapper();
wrapper.cypher();
[ I hope you notice that my version A) is easier to read and B) doesn't contain any duplicated code any more. ]
And yes, an alternative implementation of the lookup method could just go like
private Method lookupCyper(Client<?>, String methodName) {
try {
return client.getDeclaredMethod(methodName, String.class);
} catch ....
and return null;
}
... return your public cypherCBC method
But that is an "uncommon practice" in Java. In Java, we ask for permission; instead of forgiveness. Unlike other languages
if you compile the application with a Customer class which has both method,you can use reflection once to check whether the cypherCBC method available or not at runtime, then you can keep that status, you can call the method without using reflection
if(newVersion)
{
customer.cypherCBC(arg);
}
else
{
customer.cypher(arg);
}
But to write a better application,you should use two version baselines.
even though this is a small code fragment you should setup a another module to hide this Customer class and its interactions,that module should have two versions. but your main module has only single version.Now when you you deliver the application , product should be packaged with right version baseline based on compatibility for the target environment.
Although reflection works (as explained in the other answers). if you have control over the Customer class, you can try a non-reflection approach.
interface CBCCypherable {
public String cypherCBC(String pass);
}
You can now have two versions of Customer class, one that implements CBCCypherable and one that doesn't. And when you call it, it looks like this:
Customer c = new Customer();
if (c instanceof CBCCypherable) {
((CBCCypherable)c).cypherCBC(pass);
} else {
c.cypher(pass);
}
What you get with this solution is much simpler code, and as a bonus the compiler will check that you use the correct method name and parameter types. Unlike with reflection, where that's all your job, and you have to run the code to find out if something's wrong.
P.s.: I don't know if this is just sample code or you are really encrypting/hashing passwords here, but it's generally considered a bad idea to roll your own security code.

How to loop over a Class attributes in Java - from a given list (NOT reflection getDeclaredFields())?

How can I iterate over the attributes of an object, with the attribute names provided in a list/array - NOT all attributes, like using reflection & getDeclaredFields().
public class MyClass
{
public type1 att1;
public type2 att2;
public type3 att3;
public MyClass(
att1="helo";
att2="bye";
att3="morning";
);
...
public void function()
{
String myStrings[];
myStrings = new String[] { "att2", "att3" };
MyClass myobject = new MyClass();
for(var in myStrings)
{
System.out.println(var);
System.out.println(myobject.var);
System.out.println();
}
}
}
Your question is somewhat ambiguous about using reflection. If you are OK with reflection, but want specific fields only without iterating over getDeclaredFields(), then the following code should work for you:
for (String var : myStrings) {
Field field = MyClass.class.getDeclaredField(var);
field.setAccessible(true);
System.out.println(var);
System.out.println(field.get(myObject));
System.out.println();
}
Note that this code works for private fields, too. Also, keep in mind that you'll have to handle exception associated with the reflection calls.
UPDATE: Exceptions thrown in this code.
MyClass.class.getDeclaredField(var) declares a checked NoSuchFieldException. You must handle it because obviously there is no mechanism to make sure that the fields in myString match an actual implementation of MyClass.
field.get(myObject) throws a checked IllegalAccessException if the field is inaccessible. Which it should not be because of field.setAccessible(true), but you still have to catch or re-throw the exception.
There are also unchecked exceptions you may want to handle. See the javadoc for details
java.lang.Class.getDeclaredField(String)
java.lang.reflect.AccessibleObject.setAccessible(boolean) inherited by java.lang.reflect.Field
java.lang.reflect.Field.get(Object)
You probably want to use some technology that builds on top of JavaBeans / BeanInfo. Apache Commons / BeanUtils is a good starting point here.
Please refer to this previous answer of mine for more info:
https://stackoverflow.com/a/5856982/342852
But if you just want to use fields, not bean properties, here's a Java 8 method to do so:
public static Map<String, Object> getFieldProperties(Object o, Collection<String> fields) {
Class<?> type = o.getClass();
return fields.stream().map(n -> {
try {
return type.getDeclaredField(n);
} catch (NoSuchFieldException e) {
throw new IllegalStateException(e);
}
}).collect(Collectors
.toMap(
(Function<Field, String>) Field::getName,
(Function<Field, Object>) field -> {
try {
field.setAccessible(true);
return field.get(o);
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
}
}));
}
Unfortunately the checked exceptions make this more verbose than it would need to be.

Java - Get object of class depending on its name

this is my situation:
I have a method which has a String as parameter. This method has to receive an object from a class called Urls. The object it has to recieve, has the same name as the value of the String. Here is my code:
private Object getObject(String objectName){
try
{
Field field = Urls.class.getField(objectName);
}
catch (NoSuchFieldException e)
{}
catch (IllegalAccessException e)
{}
}
And here is my Urls class:
public class Urls{
public static final String[] ASTUN = new String[]{
"http://www.astun.com/camara/truchas.jpg",
"https://www.todonieve.com/photowebcam.asp?fotografia=astun/astun.jpg",
"http://www.astun.com/camara/caba%C3%B1a%20sarrios.jpg",
"http://www.astun.com/camara/sector%20sarrios.jpg",
"http://www.astun.com/camara/sector%20raca%20prad.jpg",
"http://www.astun.com/camara/sector%20aguila%20cr.jpg",
"http://www.astun.com/camara/sector%20truchas.jpg",
"http://www.astun.com/camara/sector%20llanos%20.jpg",
"http://www.astun.com/camara/llegada.jpg",
"http://www.astun.com/camara/terraza.jpg",
"http://www.astun.com/camara/panoramica.jpg",
"http://www.astun.com/camara/snow.jpg"
};
private static final String[] CANDANCHU = new String[]{
"https://www.todonieve.com/photowebcam.asp?fotografia=candanchu/candanchu.jpg",
"https://www.todonieve.com/photowebcam.asp?fotografia=CandanchuNew/CandanchuNew.jpg",
"https://www.todonieve.com/photowebcam.asp?fotografia=candanchu_rinconada/candanchu_rinco.jpg",
"https://www.todonieve.com/photowebcam.asp?fotografia=candanchu_tobazo/candanchu_tobazo.jpg"
};
}
So, that way I have a Field object, but how can I get the String[] of that field? I have read about the get(Object object) method of Field class but it seems that i doesnt do what I want to do...
EDIT: I WANT TO GET ASTUN OR CANDACHU STRING ARRAYS
Avoid reflection whenever possible. It often does more harm than good.
Put them into a map:
public class Urls {
//put your arrays here
private static final Map<String,String[]> urlsLists = new HashMap<>();
static {
urlLists.put("ASTUN", ASTUN);
urlLists.put("CANDANCHU", CANDANCHU);
}
public static String[] getUrlList(String name) {
return urlLists.get(name);
}
}
And then call it like this:
private Object getObject(String objectName){
return Urls.getUrlList(objectName);
}
Update
You loose a lot of nice stuff Java help you with, including type-safety, encapsulation and compile-time checks. Because of this it is a lot more error prone. There is a much increased risk of run-time errors and you need a bunch of extra code to handle this. Your brief example already have two catch clauses. Trust me - that will just get worse.
You can even improve type-safety more by creating an Enum to define url-types. Then you will get compile time checks that you have spelled the name right and even auto-completion all through-out your code. :)
public class Urls {
public enum UrlTypes {ASTUN; CANDANCHU;}
// ..
private static final Map<UrlTypes,String[]> urlsLists = new HashMap<>();
static {
urlLists.put(UrlTypes.ASTUN, ASTUN);
urlLists.put(UrlTypes.CANDANCHU, CANDANCHU);
}
..
public static String[] getUrlList(UrlTypes name) {
return urlLists.get(name);
}
}
Every error you can catch at compile-time instead of at run-time can save you between half an hour or half a week of work, when things get complex.
You will need something like this:
private Object getObject(String objectName){
try
{
Field field = Urls.class.getField(objectName);
Object o = field.get(null); // null works as well.
return o;
}
catch (NoSuchFieldException e)
{ e.printStackTrace(); }
catch (IllegalAccessException e)
{ e.printStackTrace(); }
}
private String[] getStringArray(String arrayName)
{
return (String[]) getObject(arrayName);
}
Usage:
Object o = getObject("ASTUN");
// or:
String[] arr = getStringArray("ASTUN");
getField will return the (reflexive) representation of the field concept in the Urls class. You then need to bind it with an actual object of that class to have access to the contents of the field in that object.
Field field = Urls.class.getFiled(objectName);
String[] values = (String[]) field.get(o);
where o is a variable of type Urls.
Note the cast to String[] as Field.get() will return an Object as it does not know the actual type. You should make sure that the type is indeed correct by using the Field.getType() method and compare that to Urls.class.
Since objects dont have names, you will need to create ypur own class, put the field variable in there, then use that instead of Object. Or use a Map for better key/value logging.

Is there something like PostConstruct for JAXB-annnotated classes?

Is there such a functionality in JAXB to perform operations on a class after it is unmarshalled i.e. after it is constructed by JAXB? If not, how could I achieve this?
You can use JAXB Unmarshal Event Callbacks which are defined in your JAXB class e.g:
// This method is called after all the properties (except IDREF) are unmarshalled for this object,
// but before this object is set to the parent object.
void afterUnmarshal( Unmarshaller u, Object parent )
{
System.out.println( "After unmarshal: " + this.state );
}
Though the the demanded functionality seems not to be present in JAXB, I managed to
achieve something which goes into the right direction:
I'm using JSR-305's #PostConstruct annotation
(it's just a nacked annotation, no functionality is provided by the JSR)
I add an unmasrshaller-listener to the unmarshaller, which gets invoked by JAXB every time an object was unmarshalled.
I inspect this object using Java reflection and search for the #PostConstruct annotation on a method
I execute the method
Tested. Works.
Here is the code. Sorry, I'm using some external reflection API to get all methods, but I think the idea is understandable:
Implementation
JAXBContext context = // create the context with desired classes
Unmarshaller unmarshaller = context.createUnmarshaller();
unmarshaller.setListener(new Unmarshaller.Listener() {
#Override
public void afterUnmarshal(Object object, Object arg1) {
System.out.println("unmarshalling finished on: " + object);
Class<?> type = object.getClass();
Method postConstructMethod = null;
for (Method m : ReflectionUtils.getAllMethods(type)) {
if (m.getAnnotation(PostConstruct.class) != null) {
if (postConstructMethod != null) {
throw new IllegalStateException(
"#PostConstruct used multiple times");
}
postConstructMethod = m;
}
}
if (postConstructMethod != null) {
System.out.println("invoking post construct: "
+ postConstructMethod.getName() + "()");
if (!Modifier.isFinal(postConstructMethod.getModifiers())) {
throw new IllegalArgumentException("post construct method ["
+ postConstructMethod.getName() + "] must be final");
}
try {
postConstructMethod.setAccessible(true); // thanks to skaffman
postConstructMethod.invoke(object);
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
throw new RuntimeException(ex);
}
}
}
});
EDIT
Added a check for #PostConstruct-annotated method, to ensure it is final.
Do you think it's a useful restriction?
Usage
Here is how the concept might be used.
#XmlAccessorType(XmlAccessType.NONE)
public abstract class AbstractKeywordWithProps
extends KeywordCommand {
#XmlAnyElement
protected final List<Element> allElements = new LinkedList<Element>();
public AbstractKeywordWithProps() {
}
#PostConstruct
public final void postConstruct() {
// now, that "allElements" were successfully initialized,
// do something very important with them ;)
}
}
// further classes can be derived from this one. postConstruct still works!
Filed a feature request
https://jaxb.dev.java.net/issues/show_bug.cgi?id=698
It's not a 100% solution, but you can always register a XmlAdapter using #XmlJavaTypeAdapter annotation
for this type.
The downside would be that you have to serialize the class yourself (?). I am not aware of any simple way of accessing and calling the default serialization mechanism. But with custom [XmlAdapter] you can control how is the type serialized and what happens before/after it.

Categories