If I have two classes with relations:
class A {
long id;
B b;
}
class B {
long id;
int property;
}
My question is: when serializing A, I hope to get only b's id, instead of the entire b object. However, I don't want this to impact the serialization of B itself. In other words, when serializing an instance of class B, the result should contain both id and property.
Any idea how this can be done with Jackson? Thanks!
You can use #JsonIgnoreProperties. The annotation is commonly used at the class level but it applies to properties as well. when applied to property, it is used to ignore properties inside the annotated property.
.
here is my test class
public static void main(String[] args)
{
ObjectMapper mapper = new ObjectMapper();
B b = new B();
b.id = 2L;
b.property = 3;
A a = new A();
a.id = 1L;
a.b = b;
try {
System.out.println("B:");
System.out.println( mapper.writeValueAsString(b));
System.out.println("A:");
System.out.println( mapper.writeValueAsString(a));
} catch (IOException e) {
e.printStackTrace();
}
}
public static class A {
public long id;
#JsonIgnoreProperties("property")
public B b;
}
public static class B {
public long id;
public int property;
}
Output:
B:
{"id":2,"property":3}
A:
{"id":1,"b":{"id":2}}
Related
I am using mockito 1.9.5 and wanting to test a class that i have posted on github.
The issue is that I need to mock the getStringFromExternalSources method.
MyClass code:
public class MyClass {
String a,b,c;
public MyClass(String a, String b, String c) {
this.a = a;
this.b = b;
this.c = c;
}
public String executeLogic (String d) {
return a + b + c + d;
}
public String getStringFromExternalSources (){
return "i got it from some place else";
}
}
My current test:
#RunWith(MockitoJUnitRunner.class)
public class MyClassTest {
#Test
public void MyClassTest() {
MyClass mc = Mockito.spy(new MyClass("a","b","c") );
Mockito.doReturn("mock").when(mc.executeLogic("real"));
Mockito.doReturn("externalString").when(mc.getStringFromExternalSources());
System.out.println(mc.executeLogic("real"));
}
}
Any pointers ?
You can mock any method using when().thenReturn() construct.
Example:
MyClass mc = Mockito.spy(new MyClass("a","b","c"));
when(mc.getStringFromExternalSource()).thenReturn("I got it from there!!");
So whenever the method 'getStringFromExternalSource()' is invoked for the mocked object mc then it will return "I got it from there!!".
if you want to Test class with different parameters then you can use #Parameters annotation to provide parameters to the class in conjunction with Parameterized runner and mention the parameters in a public static method with #Paramters annotation. A rough example would be:
#RunWith(Parameterized.class)
class SomeTestClass{
#Mock
SomeTestClass mSomeTestClassInstance;
#Parameters
public static Object provideParameters() {
Object[] objects = new Object[]{
0,
0,
2
};
return objects;
}
public SomeTestClass(Object argument1){
mArgument1 = argument1;
}
#Test
public void testSomeMethod{
Object returnValue = mSomeTestClassInstance.testSomeMethod(mArgument1);
assertequals(mArgument1,returnValue)
}
}
How to mock getStringFromExternalSources method:
public class MyClassTest {
#Test
public void MyClassTest() {
MyClass mc = mock(MyClass.class);
when(mc.executeLogic("real").thenReturn("mock");
when(mc.getStringFromExternalSources().thenReturn("externalString");
System.out.println(mc.executeLogic("real"));
}
}
class Employee
{
int id;
Employee(int id)
{
this.id = id;
}
public int getID()
{
return id;
}
public void displayID()
{
System.out.println("ID="+id);
}
}
public class Example
{
public static void main(String[] args)
{
Employee employee1 = new Employee(100);
Employee employee3 = null;
List<Employee> arrayListEx = new ArrayList<Employee>();
Set<Employee> setEx = new HashSet<Employee>();
arrayListEx.add(employee1);
arrayListEx.add(employee3);
setEx.add(employee1);
setEx.add(employee3);
}
}
Friends,
As per my understanding Set should not allow null values to get added to it.
Should the above code snippet throw compile time error for "setEx.add(employee3)" ?
Please advice, Thanks in advance.
From the Java Hashset documentation: "This class permits the null element". The file will compile.
You mentioned you believe that Set doesn't allow nulls. This depends on its implementation (link to docs)
I can't seem to be able to read a custom enum attribute using the following code:
public class CustomAttribute : Attribute
{
public CultureAttribute (string value)
{
Value = value;
}
public string Value { get; private set; }
}
public enum EnumType
{
[Custom("value1")]
Value1,
[Custom("value2")]
Value2,
[Custom("value3")]
Value3
}
...
var memInfo = typeof(CustomAttribute).GetMember(EnumType.Value1.ToString());
// memInfo is always empty
var attributes = memInfo[0].GetCustomAttributes(typeof(CustomAttribute), false);
Not sure if I am just missing something obvious here or if there is an issue with reading custom attributes in Mono/MonoMac.
You should call the GetMember() on the type that has the given member of course :) In this case that's EnumType not CustomAttribute.
Also fixed what I assume to be copy-paste error with the attribute constructor.
Complete working test code (you should know with 23k reps that we prefer these to half-made programs that we have to complete ourselves ;)):
using System;
public class CustomAttribute : Attribute
{
public CustomAttribute (string value)
{
Value = value;
}
public string Value { get; private set; }
}
public enum EnumType
{
[Custom("value1")]
Value1,
[Custom("value2")]
Value2,
[Custom("value3")]
Value3
}
class MainClass
{
static void Main(string[] args)
{
var memInfo = typeof(EnumType).GetMember(EnumType.Value1.ToString());
Console.WriteLine("memInfo length is {0}", memInfo.Length);
var attributes = memInfo[0].GetCustomAttributes(typeof(CustomAttribute), false);
Console.WriteLine("attributes length is {0}", attributes.Length);
}
}
See in operation.
When I try to serialize and deserialize a Set<ClassA<?>> of generic objects that look as follows:
public class ClassA<T> {
private ClassB datum;
private T value;
...
}
If that T happens to be an enum, it gets written as a String value. This is fine for serialization, but when I deserialize, it's not possible to know if the String value is an enum or not. Jackson then turns the resulting object into a String and you get a ClassA<String> instead of ClassA<SomeEnumType>.
Is there a configuration in Jackson to have it create some hints that the value is an enum? Or perhaps turn the enum into a JSON object rather then a string value?
Is there a configuration in Jackson to have it create some hints that the value is an enum?
It's possible to deserialize to an enum instance from a matching JSON string value. Or is this somehow not applicable to your situation?
Here is an example.
import java.util.Set;
import java.util.TreeSet;
import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
import org.codehaus.jackson.annotate.JsonMethod;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.type.TypeFactory;
public class JacksonFoo
{
public static void main(String[] args) throws Exception
{
ObjectMapper mapper = new ObjectMapper().setVisibility(JsonMethod.FIELD, Visibility.ANY);
String myEnumJson = mapper.writeValueAsString(MyEnum.MyEnum1);
System.out.println(myEnumJson);
MyEnum myEnum = mapper.readValue(myEnumJson, MyEnum.class);
System.out.println(myEnum);
Set<ClassA<MyEnum>> set = new TreeSet<ClassA<MyEnum>>();
set.add(new ClassA<MyEnum>(new ClassB("bValue7"), MyEnum.MyEnum1));
set.add(new ClassA<MyEnum>(new ClassB("bValue8"), MyEnum.MyEnum2));
String setJson = mapper.writeValueAsString(set);
System.out.println(setJson);
TypeFactory typeFactory = TypeFactory.defaultInstance();
Set<ClassA<MyEnum>> setCopy = mapper.readValue(setJson,
typeFactory.constructCollectionType(Set.class,
typeFactory.constructParametricType(ClassA.class, MyEnum.class)));
System.out.println(setCopy);
}
}
class ClassA<T> implements Comparable<ClassA<T>>
{
ClassB datum;
T value;
ClassA()
{
}
ClassA(ClassB datum, T value)
{
this.datum = datum;
this.value = value;
}
#Override
public int compareTo(ClassA<T> o)
{
return 42;
}
#Override
public String toString()
{
return String.format("ClassA: datum=%s, value=%s", datum, value);
}
}
class ClassB
{
String bValue;
ClassB()
{
}
ClassB(String bValue)
{
this.bValue = bValue;
}
#Override
public String toString()
{
return String.format("ClassB: bValue=%s", bValue);
}
}
enum MyEnum
{
MyEnum1("myEnum1", 1), MyEnum2("myEnum2", 2);
String name;
int id;
MyEnum(String name, int id)
{
this.name = name;
this.id = id;
}
}
Output:
"MyEnum1"
MyEnum1
[{"datum":{"bValue":"bValue7"},"value":"MyEnum1"},{"datum":{"bValue":"bValue8"},"value":"MyEnum2"}]
[ClassA: datum=ClassB: bValue=bValue7, value=MyEnum1, ClassA: datum=ClassB: bValue=bValue8, value=MyEnum2]
If for some reason it's necessary to have enums serialized as POJOs, then it appears custom serialization processing is required. Serializing enums with Jackson
I am trying to achieve something like the following:
class Foo
{
public virtual int Number { get; set; }
public Foo(int n)
{
Number = n; //Virtual member call in constructor
}
public void Do() {
Console.WriteLine(Number);
}
}
class Bar : Foo
{
public override int Number
{
get
{
return x.Val;
}
set
{
x.Val = value;
}
}
Bar(int n) : base(n)
{
X x = new X();
x.Val = n;
}
public void F() {
x.Something(); //changes x.Val
}
}
The reason I am doing this is because I need to propagate the call to Do when called from a variable of type Bar.
Now, I can have objects that either inherit from Foo or Bar, thus Number needs to be the way it is now, ie directly expose the Val property of x. This is because I need to allow for the following code:
Bar b = new Bar(5);
b.F(); //changes the value of Val in x
b.Do(); //Needs to print the correct, modified value
The problem here is obviously in Foo, when assigning n to Number (Virtual member call in constructor) since x from the subclass would not have been initialized yet.
What do you think is a better way to structure such a design?
I can't use this current code because I am calling a virtual member from the constructor, which causes the Object Reference not set to an Instance of an Object exception since x in Number from Bar would not have been yet initialized.
My favorite quote:
Favor composition over inheritance
I would separate underlying data from operations:
interface IMyNumber
{
int Number { get; set; }
void Something();
}
class MyNumber : IMyNumber
{
public int Number { get; set; }
public MyNumber(int n)
{
Number = n;
}
void Something() {... }
}
class MyBoxedNumber : IMyNumber
{
int Number { get { ... } set {... } }
void Something() {... }
}
class Bar
{
private IMyNumber_foo;
Bar(IMyNumber foo)
{
_foo = foo;
}
public void F() {
_foo.Something(); //changes x.Val
}
public void Do() {
Console.WriteLine(...)
}
}