How can I jackson serialize a wrapper type to and from a string?
I merged the following from two different examples their website. But the HostName type is serialized/deserialized as
{ "name" : "my.host.name.com" }
when I want it to be simply the string
"my.host.name.com"
Note that I have a lot of XName types, hence the use of the Immutables wrapper. So I would prefer a solution that keeps the amount of boiler plate down.
#Value.Immutable #AbstractName.Wrapper
public abstract class _HostName extends AbstractName { }
...
public abstract class AbstractName {
#JsonSerialize
#JsonDeserialize
#Value.Style(
// Detect names starting with underscore
typeAbstract = "_*",
// Generate without any suffix, just raw detected name
typeImmutable = "*",
// Make generated public, leave underscored as package private
visibility = Value.Style.ImplementationVisibility.PUBLIC,
// Seems unnecessary to have builder or superfluous copy method
defaults = #Value.Immutable(builder = false, copy = false))
public #interface Wrapper {}
#Value.Parameter
public abstract String name();
#Override
public String toString() { return name(); }
}
I've got this to work like below. There's an extra annotation on my name types. It's not my favorite, but it works.
#JsonDeserialize(as=HostName.class)
#Value.Immutable #AbstractName.Wrapper
public abstract class _HostName extends AbstractName { }
...
public abstract class AbstractName {
#Value.Style(
// Detect names starting with underscore
typeAbstract = "_*",
// Generate without any suffix, just raw detected name
typeImmutable = "*",
// Make generated public, leave underscored as package private
visibility = Value.Style.ImplementationVisibility.PUBLIC,
// Seems unnecessary to have builder or superfluous copy method
defaults = #Value.Immutable(builder = false, copy = false))
public #interface Wrapper {}
#JsonValue
#Value.Parameter
public abstract String name();
#Override
public String toString() { return name(); }
}
Here's a little program to run it:
public static void main(String... args) throws IOException {
ObjectMapper json = new ObjectMapper();
String text = json.writeValueAsString(HostName.of("my.host.name.com"));
System.out.println(text);
HostName hostName = json.readValue(text, HostName.class);
System.out.println(hostName);
}
Related
I have a conceptual doubt about how to organize and test code like the following, where a call to an auxiliary method is the first instruction of all the public methods of the class. My idea is make the code clean and testable.
The code is an example to try to illustrate this by a class "cache". This class has an optional prefix will be applied to all keys in the cache if it is set.
import java.util.HashMap;
public class Cache {
private HashMap<String, Integer> inMemoryCache;
private String prefix;
public Cache() {
this.inMemoryCache = new HashMap<String, Integer>();
prefix = null;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public int getValue(String key) throws NullPointerException {
String prefixedKey = applyPrefixOrDefault(key);
return inMemoryCache.get(prefixedKey);
}
public void setValue(String key, int value) {
String prefixedKey = applyPrefixOrDefault(key);
inMemoryCache.put(prefixedKey, value);
}
public boolean isCached(String key) {
String prefixedKey = applyPrefixOrDefault(key);
return inMemoryCache.containsKey(prefixedKey);
}
private String applyPrefixOrDefault(String key) {
if (prefix == null) {
return key;
} else {
return prefix + key;
}
}
public static void main (String[] arg) {
Cache cache = new Cache();
cache.setPrefix("global:");
cache.setValue("id", 4);
int value = cache.getValue("id");
System.out.println(value);
}
}
This code poses two questions to me:
If I had many methods accessing the inner hash table, would it be right separate the behavior of the cache in one class and the behavior of the prefix in other?
What would be the cleanest way to test this? Test the getValue, setValue and isCached is simple if we do not consider the prefix. With the prefix we need to test two things, the correct internal behavior of the cache and we need test also that all methods call applyPrefixOrDefault before accessing the data.
This is a common use case and I'm sure there must be some design pattern to organize this. Any idea?
To my opinion, what we miss here is a constructor that let us set the state of the cache. So I would add one as follows:
public Cache() {
this(null, new HashMap<String, Integer>());
}
public Cache(String prefix, Map<String, Integer> cache) {
this.prefix = prefix;
this.inMemoryCache = cache;
}
With this new constructor, you should be able to write test-cases for every possible cache state. I would also change the visibility of the applyPrefixOrDefault method to protected or package so that test code can access it. For instance, to test the GetValue method, I would write:
public class EmptyCacheTests {
private final Map<String, Integer> memory;
private final String prefix;
private final Cache cache;
public EmptyCacheTests() {
this.memory = new HasMap<String, Integer>();
this.prefix = "foo";
this.cache = new Cache(prefix, memory);
}
public void testGetValue() {
String key = this.cache.applyPrefixOrDefault("bar")
this.memory.put(key, 50);
result = this.cache.getValue("bar");
assertEquals(50, result, "The value retrieved is wrong!");
}
}
The point here, it to allow the test to set up the internal state of the cache, so that we can then test against many different ones.
EclipseLink version is 2.5.1
We've moved from GlassFish web-server to TomCat. This made us switch to static weaving because with TomCat dynamic weaving doesn't really work that easy.
Now that static weaving works, it seems to work quite a bit differently.
If I have an entity which sets some property directly in the constructor:
class Entity {
#Column
private String name;
public Entity() {
name = "something";
}
public String getName() {
return name;
}
}
Long story short this test will fail:
Entity e = new Entity();
assertEquals("something", e.getName()); // e.getName() returns null
This happens because getName(), after weaving, is not returning this.name anymore. Instead it calls a routing for initialization (if it's needed) and (I guess) gets the value of the property from some underlying HashMap.
But constructor is not being weaved, I even have looked into the sources of weaver and seems to be explicitly opting out of this:
/**
* Construct a MethodWeaver and allow it to process the method.
*/
#Override
public MethodVisitor visitMethod(int access, String methodName, String desc, String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, methodName, desc, signature, exceptions);
if (!alreadyWeaved) {
// skip constructors, they will not changed
if (!"<init>".equals(methodName) && !"<cinit>".equals(methodName)) {
// remaining modifications to the 'body' of the class are
// delegated to MethodWeaver
mv = new MethodWeaver(this, methodName, desc, mv);
}
}
return mv;
}
The question is, maybe I miss something here? Is it the actual reality with EclipseLink 2.5.1 that you can't use properties directly in entity's own ctor? (and it's not even mentioned anywhere, not googlable at least)
It turns out yes, we can.
But there was a problem that led us to the property being not visible to the getter.
We actually have MappedSuperclass inheritance here and we were shadowing this field in the child class. Essentially this:
class A {
#Column()
protected String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
class B extends A {
#Column()
protected String name;
// no #Override here
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
So we were just shadowing the property.
I have the following interface
#JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "className")
public interface InfoChartInformation {
public String name();
}
And the following implementation (enum):
public class InfoChartSummary {
public static enum Immobilien implements InfoChartInformation {
CITY, CONSTRUCTION_DATE;
}
public static enum Cars implements InfoChartInformation {
POWER, MILEAGE;
}
}
Then I use all of It in the following entity:
#Entity(noClassnameStored = true)
#Converters(InfoChartInformationMorphiaConverter.class)
public class TestEntity{
#Id
public ObjectId id;
#Embedded
public List<InfoChartInformation> order;
}
Jackson, in order to detect the type on the unmarshalling time, will add to every enum on the list the className.
I thought morphia would do the same, but there's no field className in the List of enum and the unmarshalling cannot be done correctly: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.ClassCastException: java.lang.String cannot be cast to com.mongodb
.DBObject
I guess the correct behavior should be to save all the enum route (package+name), not only the enum name. At least in that way the unmarshalling could be performed. There's a way morphia supports that by default or I need to create my own converter (similar to this) ?
I tried creating a Custom Converter:
public class InfoChartInformationMorphiaConverter extends TypeConverter{
public InfoChartInformationMorphiaConverter() {
super(InfoChartInformation.class);
}
#Override
public Object decode(Class targetClass, Object fromDBObject, MappedField optionalExtraInfo) {
if (fromDBObject == null) {
return null;
}
String clazz = fromDBObject.toString().substring(0, fromDBObject.toString().lastIndexOf("."));
String value = fromDBObject.toString().substring(fromDBObject.toString().lastIndexOf(".") + 1);
try {
return Enum.valueOf((Class)Class.forName(clazz), value);
} catch (ClassNotFoundException e) {
return null;
}
}
#Override
public Object encode(final Object value, final MappedField optionalExtraInfo) {
return value.getClass().getName() + "." + ((InfoChartInformation) value).name();
}
}
Then, I added the converter information to morphia morphia.getMapper().getConverters().addConverter(new InfoChartInformationMorphiaConverter());.
However, when serializing (or marshalling) the object to save it into the database, the custom converter is ignored and the Enum is saved using the default Morphia converter (only the enum name).
If I use in the TestEntity class only an attribute InfoChartInformation; instead of the List<>InfoChartInformation>, my customer converter will work. However I need support for List
Use:
public class InfoChartInformationMorphiaConverter extends TypeConverter implements SimpleValueConverter
It is a marker interface required to make your Convertor work.
I need to extend a piece of code that writes a paragraph using constant strings defined in an interface:
public class paragraphGenerator implements EnglishParaGraph(){
public StringBuffer outputParagraph = new StringBuffer();
public void generate(){
writeParagraph(PARA1);
//some long and complicated logic here
writeParagraph(PARA2);
//some long and complicated logic here
writeParagraph(PARA3);
}
public void writeParagraph(String content){
//manipulates the paragraph and puts it in stringbuffer
}
}
public interface EnglishParaGraph{
public static final String PARA1 = "Hello";
public static final String PARA2 = "Thank you";
public static final String PARA3 = "Goodbye";
}
Running generate() should write something like "Hello Thank you Goodbye".
Now I want to generate a French equivalent so the output looks something like "Bonjour Merci Salut".
According to Template Method Pattern can overwrite generate() in a subclass and change each writeParagraph's input argument, but that will repeat most of the code which is not desirable.
What's the most suitable design pattern to use here? I was told to use as little replicating code as possible.
The design of the interface and extending class is simply wrong. To be clear, interfaces are specifically used to avoid defining implementation details. The code you posted does the exact opposite of that and defines implementation details using an interface.
At worst, you want to make the interface define something like this:
public interface ParagraphSource{
public String getParagraph1Text();
public String getParagraph2Text();
public String getParagraph3Text();
}
public class EnglishSource extends ParagraphSource {
public String getParagraph1Text() {
return "Hello";
}
public String getParagraph2Text() {
return "Thank you";
}
public String getParagraph3Text() {
return "Goodbye";
}
}
public class FrenchSource extends ParagraphSource {
public String getParagraph1Text() {
return "Bonjour";
}
public String getParagraph2Text() {
return "Merci";
}
public String getParagraph3Text() {
return "Au revoir";
}
}
Then your paragraph generator can use different sources:
public class ParagraphGenerator {
public StringBuffer outputParagraph = new StringBuffer();
public void generate(ParagraphSource source){
writeParagraph(source.getParagraph1Text());
//some long and complicated logic here
writeParagraph(source.getParagraph2Text());
//some long and complicated logic here
writeParagraph(source.getParagraph3Text());
}
}
I am trying to use Ninject to implement cascading injection into a class that contains an IList field. It seems that, unless I specifically specify each binding to use in the kernel.Get method, the IList property is always injected with a list of a single default object.
The following VSTest code illustrates the problem. The first test fails because the IList field contains one MyType object with Name=null. The second test passes, but I had to specifically tell Ninject what constructor arguments to use. I am using the latest build from the ninject.web.mvc project for MVC 3.
Does Ninject specifically treat IList different, or is there a better way to handle this? Note that this seems to only be a problem when using an IList. Createing a custom collection object that wraps IList works as expected in the first test.
[TestClass()]
public class NinjectTest
{
[TestMethod()]
public void ListTest_Fails_NameNullAndCountIncorrect()
{
var kernel = new Ninject.StandardKernel(new MyNinjectModule());
var target = kernel.Get<MyModel>();
var actual = target.GetList();
// Fails. Returned value is set to a list of a single object equal to default(MyType)
Assert.AreEqual(2, actual.Count());
// Fails because MyType object is initialized with a null "Name" property
Assert.AreEqual("Fred", actual.First().Name);
}
[TestMethod()]
public void ListTest_Passes_SeemsLikeUnnecessaryConfiguration()
{
var kernel = new Ninject.StandardKernel(new MyNinjectModule());
var target = kernel.Get<MyModel>(new ConstructorArgument("myGenericObject", kernel.Get<IGenericObject<MyType>>(new ConstructorArgument("myList", kernel.Get<IList<MyType>>()))));
var actual = target.GetList();
Assert.AreEqual(2, actual.Count());
Assert.AreEqual("Fred", actual.First().Name);
}
}
public class MyNinjectModule : NinjectModule
{
public override void Load()
{
Bind<IList<MyType>>().ToConstant(new List<MyType> { new MyType { Name = "Fred" }, new MyType { Name = "Bob" } });
Bind<IGenericObject<MyType>>().To<StubObject<MyType>>();
}
}
public class MyModel
{
private IGenericObject<MyType> myGenericObject;
public MyModel(IGenericObject<MyType> myGenericObject)
{
this.myGenericObject = myGenericObject;
}
public IEnumerable<MyType> GetList()
{
return myGenericObject.GetList();
}
}
public interface IGenericObject<T>
{
IList<T> GetList();
}
public class StubObject<T> : IGenericObject<T>
{
private IList<T> _myList;
public StubObject(IList<T> myList)
{
_myList = myList;
}
public IList<T> GetList()
{
return _myList;
}
}
public class MyType
{
public String Name { get; set; }
}
lists, collections and arrays are handled slightly different. For those types ninject will inject a list or array containing an instance of all bindings for the generic type. In your case the implementation type is a class which is aoutobound by default. So the list will contain one instance of that class. If you add an interface to that class and use this one the list will be empty.