Why can't I use a getAnnotation() on a reference of Annotation? - java

We can use getAnnotations() on an interface of Annotation but not getAnnotation? Why
When I changed the interface from MyAnno to Annotation in the followng program, the compiler was not recognizing the data defined in the Annotation like the str() etc...
package british_by_blood;
import java.lang.annotation.*;
import java.lang.reflect.*;
#Retention (RetentionPolicy.RUNTIME)
#interface Hashingsnr {
String str();
int yuiop();
double fdfd();
}
public class German_by_Descent {
#Hashingsnr(str = "Annotation Example", yuiop = 100, fdfd = 4.267)
public void mymeth(){
German_by_Descent ob = new German_by_Descent();
try{
Class c = ob.getClass();
Method m = c.getMethod("mymeth");
Hashingsnr anno = m.getAnnotation(Hashingsnr.class);
System.out.println(anno.str() + " " + anno.yuiop() + " " + anno.fdfd());
}catch(NoSuchMethodException exc){
System.out.println("Method Not Found");
}
}
public static void main(String[] args) {
German_by_Descent ogb = new German_by_Descent();
ogb.mymeth();
}
}

As far as I understand, you want to change this line
Hashingsnr anno = m.getAnnotation(Hashingsnr.class);
to
Annotation anno = m.getAnnotation(Hashingsnr.class);
Of course, now anno is of type java.lang.annotation.Annotation and that interface does not define your methods str(), yuiop() and fdfd(). That's why the compiler complains in the following line.
Like with ordinary java types, you'll have to cast back to the real annotation:
System.out.println(
((Hashingsnr) anno).str() + " " +
((Hashingsnr) anno).yuiop() + " " +
((Hashingsnr) anno).fdfd());

Your program seems to be working correctly. I get the following output when i run it...
run-single:
Annotation Example 100 4.267
BUILD SUCCESSFUL (total time: 12 seconds)
I'm i missing something in your question?
I also changed the code to use the getAnnotations() method and recieved the same result...
final Annotation[] annos = m.getAnnotations();
for (Annotation anno : annos) {
if (anno instanceof Hashingsnr) {
final Hashingsnr impl = (Hashingsnr)anno;
System.out.println(impl.str() + " " + impl.yuiop() + " " + impl.fdfd());
}
}

Related

Is there a way to log which method in controller or service made the query in Spring Boot?

log photo
I need to log the following together when a method from a service is called:
class name
method name
method type
parameter's used
query used by method
controller link (optional, will figure out later)
As you can see in the picture I am able to do it but the query is logged separately. Is there a way to append the query together?
I put these in application.properties to log SQL queries:
spring.jpa.hibernate.format_sql=true
logging.level.org.hibernate.SQL=DEBUG
To log the other details I use an aspect (AOP):
#After("execution(* com.example.srs.student.StudentService.*(..))")
public void log(JoinPoint joinPoint) throws Throwable {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method currentMethod = signature.getMethod();
String className = joinPoint.getTarget().getClass().getSimpleName();
String methodName = currentMethod.getName();
String methodType = currentMethod.getReturnType().toString();
Parameter[] parameters = currentMethod.getParameters();
ArrayList<String> parameterList = new ArrayList<>();
for (Parameter parameter : parameters) {
parameterList.add(parameter.getType().getTypeName() + " - " + parameter.getName());
//parameterList2.add(parameter.toString());
}
System.out.println(className + ", " + methodName + ", " + methodType + ", "
+ parameterList.toString());
logger.info(joinPoint.getSignature().toString() + " ENNNDDDD");
}

Saving List<T> as String

I've been trying to save a list of data as Strings, but when I try a method .toString on List, it returns address in memory instead of data.
public class Item {
Integer price = 20;
Integer modelNumber = 100;
String description = "Description";
String title = "Title";
Boolean wasBought = true;
}
public static void main(String[] args) {
List<Item> data = new ArrayList<>();
data.add(new Item());
System.out.println(data.toString());
}
You need to override toString function in your Item class. Add the following snippet into your Item class:
#Override
public String toString() {
return "Item{" +
"price=" + price +
", modelNumber=" + modelNumber +
", description='" + description + '\'' +
", title='" + title + '\'' +
", wasBought=" + wasBought +
'}';
}
Output:
[Item{price=20, modelNumber=100, description='Description', title='Title', wasBought=true}]
You can convert List to json format string by json utils, e.g. jackson or fastjson, in case you may need to convert it to Objects later.
Simply use Lombok (Add Lombok jar into classpath) #ToString annotate for Item class, it will do the needful output https://projectlombok.org/features/ToString

Looking for a Straightforward Way to Parse JSON

I am attempting to parse the following JSON using Java:
{ "student_id": "123456789", "student_name": "Bart Simpson", "student_absences": 1}
What is the simplest way to accomplish this. I tried doing it the way below but think there must be an easier way.
import org.json.*
JSONObject obj = new JSONArray("report");
for(int i = 0; I < arr.length(); i++){
String studentname =
arr.getJSONObject(i).getString("student_id");
arr.getJSONObject(i).getString("student_name");
arr.getJSONObject(i).getString("student_name");
}
There's Gson:
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
public class Main {
public static void main(String[] args) {
String json = "{ \"student_id\": \"123456789\", \"student_name\": \"Bart Simpson\", \"student_absences\": 1}";
Student student = new Gson().fromJson(json, Student.class);
System.out.println(student);
}
}
class Student {
#SerializedName("student_id")
String studentId;
#SerializedName("student_name")
String studentName;
#SerializedName("student_absences")
Integer studentAbsences;
#Override
public String toString() {
return "Student{" +
"studentId='" + studentId + '\'' +
", studentName='" + studentName + '\'' +
", studentAbsences=" + studentAbsences +
'}';
}
}
Another popular one is Jackson:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Main {
public static void main(String[] args) throws Exception {
String json = "{ \"student_id\": \"123456789\", \"student_name\": \"Bart Simpson\", \"student_absences\": 1}";
Student student = new ObjectMapper().readValue(json, Student.class);
System.out.println(student);
}
}
class Student {
#JsonProperty("student_id")
String studentId;
#JsonProperty("student_name")
String studentName;
#JsonProperty("student_absences")
Integer studentAbsences;
#Override
public String toString() {
return "Student{" +
"studentId='" + studentId + '\'' +
", studentName='" + studentName + '\'' +
", studentAbsences=" + studentAbsences +
'}';
}
}
In both cases, running Main will print:
Student{studentId='123456789', studentName='Bart Simpson', studentAbsences=1}
EDIT
And without creating a Student class, you could give something like JsonPath a try.
The answer to your question depends on what you want to achieve. Your example would result in an array of strings. The previous answer results in a Java class with a property for each field. Another option is to put the values into a map.
If have written an encoder / decoder combination for this. Encoding is quite easy: use the keys and values of the map. The decoder (JSON string to map or anything else) requires a parser (best would be a tokenizer).

Xstream parsing multiple list

I have a xml file where there are multiple arrays in the root element. Whenever am trying to use the implicitcollection declaration, the xstream is only processing the last declaration and everything else remains null. In the below code the first array ERRORS remains null whereas DEBITS is parsed.
public class XMLParser {
/**
* #param args
* #throws Exception
*/
public static void main(String[] args){
String xmlString = "<DebitsWSDS xmlns=\"\"> " +
" <DEBITS> " +
" <DEBIT_ID>-1</DEBIT_ID> " +
" </DEBITS> " +
" <DEBITS> " +
" <DEBIT_ID>-2</DEBIT_ID> " +
" </DEBITS> " +
" <ERRORS> " +
" <ERROR_ID>1</ERROR_ID> " +
" </ERRORS> " +
" <ERRORS> " +
" <ERROR_ID>2</ERROR_ID> " +
" </ERRORS> " +
"</DebitsWSDS> ";
DebitsWSDS debitsWSDS;
try {
debitsWSDS = convertFeesSetXMLResultToDebitsWSDS(xmlString);
System.out.println(debitsWSDS.ERRORS==null);
System.out.println(debitsWSDS.DEBITS==null);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static DebitsWSDS convertFeesSetXMLResultToDebitsWSDS(String xml) throws Exception{
XStream xstream = new XStream(new StaxDriver());
xstream.alias("DebitsWSDS", DebitsWSDS.class);
xstream.addImplicitCollection(DebitsWSDS.class, "DEBITS");
xstream.addImplicitCollection(DebitsWSDS.class, "ERRORS");
xstream.alias("ERROR_ID", String.class);
//System.out.println(xml);
DebitsWSDS debitsWSDS =(DebitsWSDS)xstream.fromXML(xml);
return debitsWSDS;
}
}
public class DebitsWSDS {
public List<ERROR> ERRORS;
public List<DEBIT> DEBITS;
public class ERROR {
public String ERROR_ID;
}
public class DEBIT {
public String DEBIT_ID;
}
}
I'm not quite sure what you'd expect it to do. XStream is a bean/XML mapping tool, and you effectively have two XML lists mapped to the same List element in your bean. If you really want that XML strucutre I would construct your bean using a SAX parser or similar, create an empty list and let the parser callbacks add to that list.

Get the Class Name of a Field from reflection

Im going round in circles on this.
I have a class Person, eg
public class Person {
String name = "";
}
Now, I would like to introspect this class instance & figure out what Class is name declared as.
So, name = String or java.lang.String
This is my Code:
'this' is an instance of Person.
try {
String className = this.getClass().getName();
Class cls = Class.forName(className);
Field fieldlist[] = cls.getDeclaredFields();
for (int i = 0; i < fieldlist.length; i++) {
Field fld = fieldlist[i];
int mod = fld.getModifiers();
System.out.println("1. " + fld.toGenericString());
System.out.println("2. " + fld.getName());
System.out.println("3. " + fld.getGenericType() + "]");
Object oj = fld.getType();
// Says that 4: class java.lang.String
System.out.println("4: " + oj.toString());
Class c1 = oj.getClass();
// Should throw Exception
String stype = c1.getDeclaringClass().toString();
System.out.println("5. " + stype);
}
}
catch (Throwable e) {
System.err.println(e);
}
I managed to get to a part that states:
class java.lang.String
but I need it to be "java.lang.String"
Any ideas?
Try.. getType() and then getName()
fld.getType().getName()
Edit:(Aften Green Days' comment) -- Note that
fld.getType().getCanonicalName() will give same output in most cases. The output is different when innerclasses are used. Here is link came from search. Depending what you need to do with classname you may choose one of getName() or getCanonicalName()
System.out.println("3. " + fld.getType().getCanonicalName());
results in:
3. java.lang.String
I guess I solved it,
Should have done this:
String stype = fld.getType().getName();
I got the class name of a field by calling this
f.getDeclaringClass().getSimpleName()

Categories