I'm trying to find a way to generate a POJO object from the constructor of a class tagged with the #RunWith(Parameterized.class) annotation. The POJO would be used to generate the Object[] used as inputs for the constructor. Does something like this already exist? If not how could I create it?
Example code:
#RunWith(Parameterized.class)
public class Foo {
#ParameterizedTestPOJO // Annotation that would generate POJO
public Foo(String inputString, Integer inputInteger) {
// Does something
}
#Test
public testSomething() {
// Tests something
}
#Parameterized.Parameters
public static Iterable<Object[]> generateParameters() {
List<Object[]> parameters = new ArrayList<>();
// Example of how generated POJO could be used
parameters.add(new FooParameterizedPojo("input", 1).getParameters());
return parameters;
}
}
// Generated POJO
public class FooParameterizedPojo {
private String inputString;
private Integer inputInteger;
public FooParameterizedPojo(String inputString, Integer inputInteger) {
this.inputString = inputString;
this.inputInteger = inputInteger;
}
public Object[] getParameters() {
return new Object[] {inputString, inputInteger};
}
}
Edit: Maybe I could use a custom Lombok annotation? Seems promising.
Related
In Apache Johnzon, is there a way to hava a generic field that contains dynamic JSON data, not mappable to a pre-defined POJO?
In Jackson you can simply use ObjectNode as a generic container, have some JSON processing on it, and then write the whole object in JSON format.
In Jackson it works as expected using ObjectNode, here is my code:
public class JsonTest {
private String myStaticKey = "foo";
private ObjectNode jsonData;
//code to initialize ObjectNode + getters + setters
#JsonIgnore
public void addValue(String key, String value) {
jsonData.put(key, value);
}
#JsonIgnore
public String toJson() {
return new ObjectMapper().writeValueAsString(this);
}
}
public class MainTest {
public static void main(String[] args) {
JsonTest t = new JsonTest();
t.addValue("myDynamicKey", "bar");
System.out.println(t.toJson());
}
}
Expected result:
{
"myStaticKey": "foo",
"jsonData": {
"myDynamicKey": "bar"
}
}
How to read annotation which is declared over an object.
For e.g
Annotation :
AuthorInfo.java
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface AuthorInfo {
String author() default "Dushyant Kumar";
String login() default "dushyantashu";
}
What I am trying to do :
Book.java
#Data
public class Book {
private int serialNo;
private String review;
}
Main.java
public class Main {
#AuthorInfo (
author = "Barry Allen",
login = "theflash"
)
private static Book book = new Book();
public static void main(String[] args) {
showAnnotation(book);
}
private static void showAnnotation(Object object) {
// How to get values of annotation declared over this object.
}
}
My usecase is to generate this generic showAnnotation() method, that's why param is Object. How to achieve this? From what I explored, I only got ways to read annotation if it's declared over a class, or declared over a member of a class. Isn't there a way where given an object, if some annotation is present over it can be read?
Thanks
You can give a try with generics and reflection. Assume the Book class is annotated with AuthorInfo like below:
#AuthorInfo(author = "Ram", login = "ram")
public class Book {
}
Suppose if you want to know whether AuthorInfo is present in the object of Book, you can do like below. This is straight forward solution to know whether specific annotation is present in an object.
public class TestAnnotation {
public static void main(String[] args) {
Book book = new Book();
showAnnotation(book);
}
private static <T> void showAnnotation(T t) {
Class<? extends Object> aClass = t.getClass();
if (aClass.isAnnotationPresent(AuthorInfo.class)) {
System.out.println("AuthorInfo annotation present");
AuthorInfo authorInfo = aClass.getAnnotation(AuthorInfo.class);
System.out.println(authorInfo.author());
System.out.println(authorInfo.login());
}
}
}
Suppose, if you want to know all annotations on that object, something like below helps:
private static <T> void showAnnotation(T t) {
Class<? extends Object> aClass = t.getClass();
for (Annotation annotation : aClass.getAnnotations()) {
System.out.println(annotation.toString());
}
}
You can retrieve the object class and then explore it. Via Reflection you could get its fields and methods also, and check if any has annotations on it.
Annotations can be read using Reflection API. Like
Class<Main> clazz = Main.class;
Method[] methods = clazz.getDeclaredMethods();
Field[] fields = clazz.getDeclaredFields();
for (Method method : methods) {
Annotation[] annotation = method.getDeclaredAnnotations();
}
for (Field field : fields) {
//This will get #AuthorInfo annotation on book
Annotation[] annotation = field.getDeclaredAnnotations();
//This will get #Data annotation on Book class
Annotation[] annotationsOnFieldClass = field.getClass().getDeclaredAnnotations();
}
clazz.getDeclaredAnnotations();
Currently I have form like below:
public class Form {
private String listOfItems;
public String getListOfItems() {
return listOfItems;
}
public void setListOfItems(String listOfItems) {
this.listOfItems= listOfItems;
}
}
For instanse listOfItems equals to the following string "1,2,3".
The goal is to serialize this form to following format:
{
"listOfItems": [1, 2, 3]
}
It would be good to know how to correctly do such thing? As I know it is possible to create some custom serializer then mark appropriate getter method with it, like this #JsonSerialize(using = SomeCustomSerializer).
But not sure whether it is correct approach, probably any default implementations already exist.
If you can edit your Form class:
public class Form {
private String listOfItems;
public String getListOfItems() {
return listOfItems;
}
public void setListOfItems(String listOfItems) {
this.listOfItems = listOfItems;
}
#JsonProperty("listOfItems")
public List<Integer> getArrayListOfItems() {
if (listOfItems != null) {
List<Integer> items = new ArrayList();
for (String s : listOfItems.split(",")) {
items.add(Integer.parseInt(s)); // May throw NumberFormatException
}
return items;
}
return null;
}
}
By default Jackson looks for getters for serializing. You can override this by using #JsonProperty annotation.
ObjectMapper mapper = new ObjectMapper();
Form form = new Form();
form.setListOfItems("1,2,3");
System.out.print(mapper.writeValueAsString(form));
Outputs:
{"listOfItems":[1,2,3]}
I would like to perform a JUnit Parametrized test with data being external.
I have a list of objects and just need to know how I can convert that to a collection of object arrays. I see the below stack overflow question, but I want to add data from a file which is read from my method.
Parameterized JUnit tests with non-primitive parameters?
Working code: something like this:
#RunWith(Parameterized.class)
public class sampletest {
private BranchMailChildSample branch;
public sampletest(BranchMailChildSample branch)
{
this.branch = branch;
}
#Parameters
public static Collection<Object[]> data()
{
String excel = "C:\\Resources\\TestData\\ExcelSheets\\BranchMail\\branchmail_TestData.xlsx";
ExcelMarshallerTool tool = new ExcelMarshallerTool(excel);
List<BranchMailChildSample> items = tool.unmarshallExcel(BranchMailChildSample.class);
//RIGHT HERE I NEED HELP: Convert list to Collection<Object[]>
//return items as Collection of object arrays
}
#Test
public void test()
{
System.out.println(branch.toString());
}
}
You don't have to convert the list.
#RunWith(Parameterized.class)
public class SampleTest {
#Parameters(name = "{0}")
public static List<BranchMailChildSample> data() {
String excel = "C:\\Resources\\TestData\\ExcelSheets\\BranchMail\\branchmail_TestData.xlsx";
ExcelMarshallerTool tool = new ExcelMarshallerTool(excel);
return tool.unmarshallExcel(BranchMailChildSample.class);
}
#Parameter(0)
public BranchMailChildSample branch;
#Test
public void test() {
System.out.println(branch.toString());
}
}
I used field injection, because it needs less code than constructor injection. Setting the name to the object under test prints more helpful output. Please have a look at the documentation of the Parameterized runner.
You can use constructor injection if you don't like the public field.
#RunWith(Parameterized.class)
public class SampleTest {
#Parameters(name = "{0}")
public static List<BranchMailChildSample> data() {
String excel = "C:\\Resources\\TestData\\ExcelSheets\\BranchMail\\branchmail_TestData.xlsx";
ExcelMarshallerTool tool = new ExcelMarshallerTool(excel);
return tool.unmarshallExcel(BranchMailChildSample.class);
}
private final BranchMailChildSample branch;
public SampleTest(BranchMailChildSample branch) {
this.branch = branch;
}
#Test
public void test() {
System.out.println(branch.toString());
}
}
That's why I would suggest you to use TestNG instead if possible.
It's work the same as JUnit but you can use a internal or external DataProvider, execute methods at a given order... It is much more convenient to use
//This method will provide data to any test method that declares that its Data Provider
//is named "test1"
#DataProvider(name = "test1")
public Object[][] createData1() {
return new Object[][] {
{ "Cedric", new Integer(36) },
{ "Anne", new Integer(37)},
};
}
//This test method declares that its data should be supplied by the Data Provider
//named "test1"
#Test(dataProvider = "test1")
public void verifyData1(String n1, Integer n2) {
System.out.println(n1 + " " + n2);
}
I got it to work doing this:
List<BranchMailChildSample> items = tool.unmarshallExcel(BranchMailChildSample.class);
Collection<Object[]> data = new ArrayList<Object[]>();
for(BranchMailChildSample item : items)
{
Object[] objItem = new Object[] { item };
data.add(objItem);
}
return data;
Actually, if you use JUnit 4.12 and the theories runner, something like this should just work:
#RunWith(Theories.class)
public class MyTest
{
#DataPoints public static List<MyClass> myFunctionThatReturnsTestData()
{
// TODO
}
#Theory
public void canDoTheThing(MyClass m) throws Exception {
I have JSON, with differents levels field, so I want to convert to a single JSON with fields with one level for example:
{
"prop1":"value1",
"prob2":"value2",
"prop3": {
"prop4":"value4",
"prop5":"value5"
}
... many level fields
}
result
{
"prop1":"value1",
"prop2":"value2",
"prop4":"value4",
"prop5":"value5"
.......
}
I'm using Jackson with annotation #JsonProperty("field"), I haven't problem wih fields of first level , but I donĀ“t know how to access field where to into more inside JSON , for this example are prop4 and prop5.
JsonUnwrapped is the annotation to use, it even works for multi-level nesting. For example:
#RunWith(JUnit4.class)
public class Sample {
#Test
public void testName() throws Exception {
SampleClass sample = new SampleClass("value1", "value2", new SubClass("value4", "value5", new SubSubClass("value7")));
new ObjectMapper().writeValue(System.out, sample);
}
#JsonAutoDetect(fieldVisibility=Visibility.ANY)
public static class SampleClass {
private String prop1;
private String prop2;
#JsonUnwrapped
private SubClass prop3;
public SampleClass(String prop1, String prop2, SubClass prop3) {
this.prop1 = prop1;
this.prop2 = prop2;
this.prop3 = prop3;
}
}
#JsonAutoDetect(fieldVisibility=Visibility.ANY)
public static class SubClass {
private String prop4;
private String prop5;
#JsonUnwrapped
private SubSubClass prop6;
public SubClass(String prop4, String prop5, SubSubClass prop6) {
this.prop4 = prop4;
this.prop5 = prop5;
this.prop6 = prop6;
}
}
#JsonAutoDetect(fieldVisibility=Visibility.ANY)
public static class SubSubClass{
private String prop7;
public SubSubClass(String prop7) {
this.prop7 = prop7;
}
}
}
will generate
{"prop1":"value1","prop2":"value2","prop4":"value4","prop5":"value5","prop7":"value7"}
Try implementing the #JsonUnwrapped annotation. More information at http://jackson.codehaus.org/1.9.9/javadoc/org/codehaus/jackson/annotate/JsonUnwrapped.html