How to serialize polymorphic list with element type names as xml element names in Jackson - jackson-dataformat-xml

I have a list of objects with common base class. I wish to serialize (and deserialize) this list so that each list element is serialized with its root element equal to the name of the type and not have the wrapping object around the element.
I tried using JsonTypeInfo with Id.Name and As.WRAPPER_OBJECT which produces an XML with proper element names but (obviously) with another layer of XML elements (from the list itself).
package zm.study.xmlserialize.jackson;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
public class JacksonListTest4 {
public static class L {
public List<A> as = new ArrayList<>();
}
#JsonTypeInfo(use = Id.NAME, include=As.WRAPPER_OBJECT)
#JsonSubTypes({
#JsonSubTypes.Type(value=B.class, name="b"),
#JsonSubTypes.Type(value=C.class, name="c"),
})
public static abstract class A {
}
public static class B extends A {
}
public static class C extends A {
}
#Test
public void test() throws Exception
{
L l = new L();
l.as.add(new B());
l.as.add(new C());
new XmlMapper().enable(SerializationFeature.INDENT_OUTPUT)
.writeValue(System.out, l);
}
}
I would like to get:
<L>
<as>
<b/>
<c/>
</as>
</L>
Instead I get:
<L>
<as>
<as>
<b/>
</as>
<as>
<c/>
</as>
</as>
</L>

If you know what you want it to look like you're better off writing an XSD and then using a tool like JAXB to create a serialization/deserialization Java object.

Related

Spring + QueryDsl + Mockito: How to write a unit test case for a simple function

I have the following function in my service.
public boolean checkNameUnique(String name) {
QEntity qEntity = QEntity.entity;
BooleanExpression nameUniquePredicate = qEntity.name.eq(name);
long count = entityReadRepository.count(nameUniquePredicate);
return count == 0;
}
It just checks if the name already exists in db. That needs to be unique, so it returns true if does not already exist and false if it does.
Now how do I write a mockito unit test case for this? I am new to Mockito and writing unit test cases, hence the question.
My reading on Mockito has lead me to write something on the lines of
when(entityReadRepository.count(nameUniquePredicate)).thenReturn(1);
and then call the function to be tested. But that doesn't make any sense.
Entity is Hibernate entity which corresponds to a table in the DB
entityReadRepository extends JpaRepository and QueryDslPredicateExecutor. QEntity is the Q object generated by QueryDsl's plugin.
A unit test would normally mock out any external dependencies, in your case entityReadRepository. If you want to do actual db call it would be classed as integration test.
Your method should return two different values depending on the entityReadRepository response and this is what you would stub in order to unit test it. You were on a good path trying:
when(entityReadRepository.count(any(BooleanExpression.class))).thenReturn(1l);
The problem you have is that you have a lot of static calls and objects in your method and that can't be handled gracefully. One option is to use tools like Powermockito where you can mock behaviour of static methods. If you prefer to stick with mockito you could extract static piece of code to a separate method and create a spy of your class under test:
package com.slavpilus;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.when;
#RunWith(MockitoJUnitRunner.class)
public class TPresenterTest {
#InjectMocks
#Spy
private ClassUnderTest target = new ClassUnderTest();
#Before
public void setUp() {
doReturn(null).when(target).getUniqueNamePredicate();
}
#Mock
private YourRepositoryDependency entityReadRepository;
#Test
public void checkNameUniqueShouldBeTrueIfNameNotInDatabase() {
when(entityReadRepository.count(any())).thenReturn(0l);
boolean isUnique = target.checkNameUnique("anyName");
Assert.assertTrue(isUnique);
}
#Test
public void checkNameUniqueShouldBeFalseIfNameFoundInDatabase() {
when(entityReadRepository.count(any())).thenReturn(1l);
boolean isUnique = target.checkNameUnique("anyName");
Assert.assertFalse(isUnique);
}
}
and your production code would look something like that:
public boolean checkNameUnique(String name) {
BooleanExpression nameUniquePredicate = getUniqueNamePredicate();
long count = entityReadRepository.count(nameUniquePredicate);
return count == 0;
}
protected BooleanExpression getUniqueNamePredicate() {
QEntity qEntity = QEntity.entity;
return qEntity.name.eq(name);
}
This approach however leaves you with some code untested as getUniqueNamePredicate method is skipped entirely during the test execution.

Instantiate a field level HashMap in JCodeModel

I want to declare and instantiate a HashMap in one go in JCodeModel.
I do:
jc.field(JMod.PRIVATE, HashMap.class, "initAttributes");
which declares it but doesn't instantiate it. How do I instantiate it?
Thanks
In the simplest case, you can just append the initialization directly to your creation of the field:
jc.field(JMod.PRIVATE, HashMap.class, "initAttributes")
.init(JExpr._new(codeModel.ref(HashMap.class)));
Some further hints:
Considering that you should usually program to an interface, it is a good practice to declare the variable using a type that is "as basic as possible". You should hardly ever declare a variable as
private HashMap map;
but basically always only as
private Map map;
because Map is the interface that is relevant here.
You can also add generics in JCodeModel. These usually involve some calls to narrow on certain types. It is a bit more effort, but it will generate code that can be compiled without causing warnings due to the raw types.
An example is shown here. (It uses String as the key type and Integer as the value type of the map. You may adjust this accordingly)
import java.util.HashMap;
import java.util.Map;
import com.sun.codemodel.CodeWriter;
import com.sun.codemodel.JClass;
import com.sun.codemodel.JCodeModel;
import com.sun.codemodel.JDefinedClass;
import com.sun.codemodel.JExpr;
import com.sun.codemodel.JMod;
import com.sun.codemodel.writer.SingleStreamCodeWriter;
public class InitializeFieldInCodeModel
{
public static void main(String[] args) throws Exception
{
JCodeModel codeModel = new JCodeModel();
JDefinedClass definedClass = codeModel._class("com.example.Example");
JClass keyType = codeModel.ref(String.class);
JClass valueType = codeModel.ref(Integer.class);
JClass mapClass =
codeModel.ref(Map.class).narrow(keyType, valueType);
JClass hashMapClass =
codeModel.ref(HashMap.class).narrow(keyType, valueType);
definedClass.field(JMod.PRIVATE, mapClass, "initAttributes")
.init(JExpr._new(hashMapClass));
CodeWriter codeWriter = new SingleStreamCodeWriter(System.out);
codeModel.build(codeWriter);
}
}
The generated class looks as follows:
package com.example;
import java.util.HashMap;
import java.util.Map;
public class Example {
private Map<String, Integer> initAttributes = new HashMap<String, Integer>();
}

Missing AST Classes in Global Transform

I am writing a transform to add some extra annotations to fields that already have a specific annotation.
I have the following configuration that I provide to the compiler
import groovy.transform.CompileStatic
import groovy.transform.PackageScope
import org.codehaus.groovy.ast.ASTNode
import org.codehaus.groovy.ast.AnnotationNode
import org.codehaus.groovy.ast.ClassHelper
import org.codehaus.groovy.ast.FieldNode
import org.codehaus.groovy.control.CompilePhase
import org.codehaus.groovy.control.SourceUnit
import org.codehaus.groovy.transform.AbstractASTTransformation
import org.codehaus.groovy.transform.GroovyASTTransformation
#CompileStatic
#GroovyASTTransformation(phase = CompilePhase.CONVERSION)
class InjectorTransform extends AbstractASTTransformation {
#Override void visit(ASTNode[] nodes, SourceUnit source) {
source.AST.classes*.fields.flatten().each {
def field = it as FieldNode
def found = field.annotations.find { it.classNode.name == 'javax.inject.Inject' }
if (found) {
field.addAnnotation(new AnnotationNode(ClassHelper.make(PackageScope)))
}
}
}
}
withConfig(configuration) {
ast(CompileStatic)
ast(new InjectorTransform())
}
I provide this to gradle using groovyOptions.configurationScript
The transform runs as expected but source.AST.classes only returns a single class. This class always the first alphabetical class of all the classes that are being compiled. For example if I have classes Bar and Foo, it will return Bar. If I create another class called Alpha, Alpha will be returned.
My question is what could be causing the transform to not be getting all of the classes? Is there an issue with adding a global transform this way, or something that could be preventing the rest of the classes for being visible?
I solved this problem by using the inline method instead of creating a class inside of config script. I'm not sure why the original method didn't work and maybe it's a bug but here the solution.
import groovy.transform.CompileStatic
import groovy.transform.PackageScope
import org.codehaus.groovy.ast.AnnotationNode
import org.codehaus.groovy.ast.ClassHelper
import org.codehaus.groovy.ast.FieldNode
import static org.codehaus.groovy.control.CompilePhase.CONVERSION
withConfig(configuration) {
ast(CompileStatic)
inline(phase: CONVERSION) { source, context, classNode ->
source.AST.classes*.fields.flatten().each {
def field = it as FieldNode
def found = field.annotations.find { it.classNode.name == 'Inject' }
if (found) {
field.addAnnotation(new AnnotationNode(ClassHelper.make(PackageScope)))
}
}
}
}

SPEL (Spring Expression Language) Collection Selection calling methods/functions in selection

I am trying to write simple validation rules with SpEL
I want to be able to say something like, "Do any elements in the List have a value greater then x". Simple case works fine, but I wanted to extend it to get the absolute value first and then do the greater than test
If I try to call methods or functions as part of the criteria to select from a collection. it seems to loose the context that I am working with an item in the collection
import java.util.Arrays;
import java.util.List;
public class BeanClass {
private final List<ListOf> list;
public BeanClass(ListOf... list){
this.list = Arrays.asList(list);
}
public List<ListOf> getList(){
return list;
}
}
public class ListOf {
private final double value;
public ListOf(double v) {
this.value = v;
}
public double getValue() {
return value;
}
}
import org.junit.Test;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import static org.junit.Assert.assertTrue;
public class SpelTest {
#Test
public void test(){
ExpressionParser parser = new SpelExpressionParser();
// works as expected
Expression expression1 = parser.parseExpression("list.?[ value>2 ].size()!=0");
assertTrue(expression1.getValue(new BeanClass(new ListOf(1.1), new ListOf(2.2)), Boolean.class));
Expression expression2 = parser.parseExpression("list.?[ T(java.lang.Math).abs(value) > 2 ].size()!=0");
// get this error:
//org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 5): Property or field 'value' cannot be found on object of type 'BeanClass' - maybe not public?
assertTrue(expression2.getValue(new BeanClass(new ListOf(1.1), new ListOf(-2.2)), Boolean.class));
}
}
I have played with defining my own function and registering it
Experimented with #this as well
Looks like an issue, though: https://jira.spring.io/browse/SPR-12035
As a cunclusion: you can't use method invocation within selectionExpression for items.
You need to add #this to refer the current item, for example:
Expression expression2 = parser.parseExpression("list.?[ T(java.lang.Math).abs(#this.getValue()) > 2 ].size()!=0");

How to write annotation processor to raise a warning message if a java source is calling an annotated method

Here is my requirement in Java 6: I am using Eclipse JUNO.
Annotate a method with a custom annotation.
During compilation, raise warning message if a method is calling the
annotated method.
I am looking for something like #Deprecated annotation.
This is what I have done:
Wrote a custom annotation.
Wrote an annotation processor to read and process the methods with
the annotation.
Created a jar and added it in annotation processor path. My sample code (see below) raises the warning message in the annotated method. But it is not my requirement.
What I couldn’t do:
I could not get the calling methods. I want to raise the warning
message in those calling methods.
My sample code:
Custom annotation:
package tool.apichecks;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Retention(RetentionPolicy.SOURCE)
#Target({ ElementType.METHOD })
public #interface HighCostMethod {
String altMethod();
}
Annotation Processor:
package tool.apichecks;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;
#SupportedAnnotationTypes({ "tool.apichecks.HighCostMethod" })
public class MethodProcessor extends AbstractProcessor {
private enum MethodType {
HIGH_COST(HighCostMethod.class.getName());
private String name;
private MethodType(String name) {
this.name = name;
}
private static MethodType getMethodType(String name) {
MethodType methodType = null;
for (MethodType methodType2 : MethodType.values()) {
if (methodType2.name.equals(name)) {
methodType = methodType2;
break;
}
}
return methodType;
}
}
private ProcessingEnvironment processingEnvironment;
#Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
this.processingEnvironment = processingEnvironment;
}
#Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnvironment) {
if (!roundEnvironment.processingOver()) {
for (TypeElement annotation : annotations) {
final Set<? extends Element> elements = roundEnvironment
.getElementsAnnotatedWith(annotation);
MethodType methodType = MethodType.getMethodType(annotation
.toString());
for (Element element : elements) {
switch (methodType) {
case HIGH_COST: {
processHighCostMethod(element);
break;
}
}
}
}
}
return true;
}
protected void processHighCostMethod(Element element) {
HighCostMethod highCostMethod = element
.getAnnotation(HighCostMethod.class);
/* TODO This warns the annotated method itself. I don't want this. I want to warn the methods that calls this method */
processingEnvironment
.getMessager()
.printMessage(
Kind.WARNING,
String.format(
"Do not use high cost method %s. Instead use %s method.",
element, highCostMethod.altMethod()), element);
}
}
Using an AnnotationProcessor will only work on the files containing the annotations or overriding methods, but not calling methods. Maybe there's a way around this, but then you will probably be limited by projects, because the processor only looks at one project at a time.
I guess you need to write an Eclipse plugin with a builder, that analyses code in all files and checks called methods for annotations.
That a lot more work than an annotation processor, but you also have more options. E.g. you could implement a quick fix for the error markers.

Resources