I have an existing object that I want to serialize in MongoDB using Java + POJO codec. For some reason the driver tries to create an instance of an enum instead of using valueOF:
org.bson.codecs.configuration.CodecConfigurationException: Failed to decode 'phase'. Failed to decode 'value'. Cannot find a public constructor for 'SimplePhaseEnumType'.
at org.bson.codecs.pojo.PojoCodecImpl.decodePropertyModel(PojoCodecImpl.java:192)
at org.bson.codecs.pojo.PojoCodecImpl.decodeProperties(PojoCodecImpl.java:168)
at org.bson.codecs.pojo.PojoCodecImpl.decode(PojoCodecImpl.java:122)
at org.bson.codecs.pojo.PojoCodecImpl.decode(PojoCodecImpl.java:126)
at com.mongodb.operation.CommandResultArrayCodec.decode(CommandResultArrayCodec.java:52)
The enumeration:
public enum SimplePhaseEnumType {
PROPOSED("Proposed"),
INTERIM("Interim"),
MODIFIED("Modified"),
ASSIGNED("Assigned");
private final String value;
SimplePhaseEnumType(String v) {
value = v;
}
public String value() {
return value;
}
public static SimplePhaseEnumType fromValue(String v) {
for (SimplePhaseEnumType c: SimplePhaseEnumType.values()) {
if (c.value.equals(v)) {
return c;
}
}
throw new IllegalArgumentException(v);
}}
And the class the uses the enumeration (only showing the relevant fields):
public class SpecificPhaseType {
protected SimplePhaseEnumType value;
protected String date;
public SimplePhaseEnumType getValue() {
return value;
}
public void setValue(SimplePhaseEnumType value) {
this.value = value;
}}
I was looking for a way to maybe annotate the class to tell the driver to use a different method to serialize / deserialize those fields when they are encountered. I know how to skip them during the serialization / deserialization but that doesn't fix the problem:
public class SpecificPhaseType {
#BsonIgnore
protected SimplePhaseEnumType value;
Any help on where I could look (code, documentation)?. I already checked PojoQuickTour.java, MongoDB Driver Quick Start - POJOs and POJOs - Plain Old Java Objects
Thanks!
--Jose
I figured out what to do, you first need to write a custom Codec to read and write the enum as a String (an ordinal is another option if you want to save space, but string was more than OK with me):
package com.kodegeek.cvebrowser.persistence.serializers;
import com.kodegeek.cvebrowser.entity.SimplePhaseEnumType;
import org.bson.BsonReader;
import org.bson.BsonWriter;
import org.bson.codecs.Codec;
import org.bson.codecs.DecoderContext;
import org.bson.codecs.EncoderContext;
public class SimplePhaseEnumTypeCodec implements Codec<SimplePhaseEnumType>{
#Override
public SimplePhaseEnumType decode(BsonReader reader, DecoderContext decoderContext) {
return SimplePhaseEnumType.fromValue(reader.readString());
}
#Override
public void encode(BsonWriter writer, SimplePhaseEnumType value, EncoderContext encoderContext) {
writer.writeString(value.value());
}
#Override
public Class<SimplePhaseEnumType> getEncoderClass() {
return SimplePhaseEnumType.class;
}
}
Then you need to register the new codec so MongoDB can handle the enum using your class:
/**
* MongoDB could not make this any simpler ;-)
* #return a Codec registry
*/
public static CodecRegistry getCodecRegistry() {
final CodecRegistry defaultCodecRegistry = MongoClient.getDefaultCodecRegistry();
final CodecProvider pojoCodecProvider = PojoCodecProvider.builder().register(packages).build();
final CodecRegistry cvePojoCodecRegistry = CodecRegistries.fromProviders(pojoCodecProvider);
final CodecRegistry customEnumCodecs = CodecRegistries.fromCodecs(
new SimplePhaseEnumTypeCodec(),
new StatusEnumTypeCodec(),
new TypeEnumTypeCodec()
);
return CodecRegistries.fromRegistries(defaultCodecRegistry, customEnumCodecs, cvePojoCodecRegistry);
}
Jackson makes it easier to register custom serializer/ deserializer with annotations like #JsonSerializer / #JsonDeserializer and while Mongo forces you to deal with the registry. Not a big deal :-)
You can peek at the full source code here. Hope this saves some time to anyone who has to deal with a similar issue.
Related
I have a config file with key value pair as
language = "IN"
and i have multiple page object enum files with name as
PageObject_US,PageObject_UK,PageObject_IN
every page object enum file has constants that can be accessed using for example
PageObjects_US.String.lable
but what i want to achieve is a way to create something like below
take the parameter from config file store it in a string
like String language = "IN"
Then concatenate using "PageObjects_" + language to get (PageObjects_IN)
so that the returned value can be used to fetch the constants from PageObjects_IN.String.label.
following is the code block:
if(!ENV.equalsIgnoreCase("development") && VALIDATION.equalsIgnoreCase("yes")) {
Elements.ByTitle(webDriver,PageObjects_IN.GREAT.label);
Elements.ByID(webDriver, PageObjects_IN.COUNTER.label);
}
In the above i want to use enum file PageObjects_IN at run time as i have many enum files
below is the enum
public enum PageObjects_IN {
// Text
GREAT("great"),
COUNTER("counter");
public final String lable;
PageObjects_IN(final String lable) {
this.lable = lable;
}
}
This is possible (using reflection) but strongly not recommended as it eliminates the efficiency of Java language constructs.
Not recommended way
Say you have a package click.webelement.cucumber.po where you store
public enum PO_EN {
GREAT("great_en"),
COUNTER("counter_en");
public final String label;
PO_EN(String label){
this.label = label;
}
}
and
public enum PO_IN {
GREAT("great_in"),
COUNTER("counter_in");
public final String label;
PO_IN(String label){
this.label = label;
}
}
Then to take a value you can do something like this:
String lang = "EN";
// Take class
Class clazz = Class.forName("click.webelement.cucumber.po.PO_" + lang);
// Find an object that represent enum constant
Object val = Arrays
.stream(clazz.getEnumConstants()).filter(o -> "GREAT".equals(o.toString()))
.findAny()
.get();
// Take field value for that object
Field f = clazz.getField("label");
System.out.println(f.get(val));
This is error-prone approach and you would not have benefit from compile phase.
Recommended approach - 1
Instead of having enum use classes.
public abstract class PO {
public abstract String great();
public abstract String counter();
}
and
public class PO_EN extends PO{
#Override
public String great() {
return "great_en";
}
#Override
public String counter() {
return "counter_en";
}
}
and
public class PO_IN extends PO{
#Override
public String great() {
return "great_in";
}
#Override
public String counter() {
return "counter_in";
}
}
so your test would be much simpler
String lang = "EN";
Class clazz = Class.forName("click.webelement.cucumber.po.PO_" + lang);
PO val = (PO) clazz.getDeclaredConstructor().newInstance();
System.out.println(val.great());
Recommended approach - 2
You can utilize PageFactory harness for your page objects and use this lib to parametrize your locators, like (if you use test ng):
#DataProvider(name = "languages")
Object[][] dataProvider(){
return new Object[][]{
{"en", "great_en", "counter_en"},
{"in", "great_in", "counter_in"}
};
}
#Test(dataProvider = "languages")
public void testPage(String language, String great, String counter){
DefaultParameterProvider
.properties
.set(Map.of("p.great", great, "p.counter", counter));
MyPage myPage = new MyPage(driver);
...
}
Where your page would be like this:
public class MyPage extends PageObjectParameterized {
#FindByParameterized(xpath = "//button[#name='{wec:p.great}']")
WebElement great;
#FindByParameterized(xpath = "//label[text()='{wec:p.counter}']")
WebElement counter;
#FindBy(xpath = "//input")
WebElement input;
public MyPage(SearchContext searchContext) {
super(searchContext);
}
}
Inspired by FilenameFilter.java, I want to use similar approach/design pattern to solve my problem. I have select files from sftp server based on:
If it is older than n days
If it is older than n days and its name is in certain pattern.
I have defined a functional interface SemanticFileFilter as below:
public interface SftpFileFilter
{
boolean accept(LsEntry sftpFile);
}
LsEntry for sftp is basically something like File in java.
Wanted to define SftpFileFilterFactory to get all implementation of SftpFileFilter at one place like below:
public class SftpFileFilterFactory
{
public static final SftpFileFilter OLD_FILE_FILTER = new SftpFileFilter()
{
//ERROR: because Interface function method should take only 1 parameter
//#Override
public boolean accept(LsEntry lsEntry,int nDays)
{
//checks if files if older than nDays
}
};
public static final SftpFileFilter PATTERN_MATCH_OLD_FILE_FILTER = new SftpFileFilter()
{
//ERROR: because Interface function method should take only 1 parameter
//#Override
public boolean accept(LsEntry lsEntry,int nDays, String pattern)
{
//checks if files if older than nDays and matches pattern "pattern"
}
};
}
How do I design my interface's function method or factory implementation so that in future if similar more filters needs to be defined, I don't need to bother much in code changes but just define new filter.
Also we should be able to chain filters. That is to say define one filter for older files and another for pattern matching. If both needs to used they should be able to chained together and hence both could be used.
Your problem reminds Command design pattern. You need to implement different conditions and to provide additional parameters you can use constructors and create classes or use Java 8 lambda expressions. See below example:
import java.util.ArrayList;
import java.util.List;
public class DesignPatterns {
public static void main(String[] args) {
List<SftpFileFilter> filters = new ArrayList<>();
filters.add(new OlderThanNDaysFilter(10));
filters.add(new NameSftpFileFilter("tmp.txt"));
// you can use lambda as well
filters.add((file) -> file.getName().length() > 0);
}
}
interface SftpFileFilter {
boolean accept(LsEntry sftpFile);
}
class OlderThanNDaysFilter implements SftpFileFilter {
private final int days;
public OlderThanNDaysFilter(int days) {
this.days = days;
}
#Override
public boolean accept(LsEntry sftpFile) {
return sftpFile.isOlder(days);
}
}
class NameSftpFileFilter implements SftpFileFilter {
private final String name;
public NameSftpFileFilter(String name) {
this.name = name;
}
#Override
public boolean accept(LsEntry sftpFile) {
return sftpFile.getName().equals(name);
}
}
These objects are too small and there is not need to create factory for it. You can create and use them if it is necessary. Of course, you can create factory which creates some predefined filters:
class ConditionFactory {
private static final SftpFileFilter OLDER_THAN_TEN = new OlderThanNDaysFilter(10);
private static final SftpFileFilter PASSWORDS_FILE = new NameSftpFileFilter("passwords.txt");
public SftpFileFilter createOlderThan10Days() {
return OLDER_THAN_TEN;
}
public SftpFileFilter createPasswordsFile() {
return PASSWORDS_FILE;
}
public SftpFileFilter createNameFilter(final String name) {
return new NameSftpFileFilter(Objects.requireNonNull(name));
}
public SftpFileFilter createOlderThan(final int days) {
return new OlderThanNDaysFilter(days);
}
}
It is a good separation between filter implementations and client code which does not know anything how filtering by name is implemented and can be easily exchanged.
In Java 8 you can use java.util.function.Predicate directly or extend it by your interface:
interface SftpFileFilter extends Predicate<LsEntry> {
boolean accept(LsEntry sftpFile);
#Override
default boolean test(LsEntry lsEntry) {
return accept(lsEntry);
}
}
I created a factory pattern in my class.
In this class I injected classes which implements Command interface based on incoming String parameter.
Factory class
#Component
#RequiredArgsConstructor
public class CommandFactory {
private final ACommand aCommand;
private final BCommand bCommand;
private final CCommand cCommand;
private final DCommand dCommand;
private final ECommand eCommand;
private final FCommand fCommand;
public Command createCommand(String content) {
if (aCommand.isMatching(content)) {
return aCommand;
} else if (bCommand.isMatching(content)) {
return bCommand;
} else if (cCommand.isMatching(content)) {
return cCommand;
} else if (dCommand.isMatching(content)) {
return dCommand;
} else if (eCommand.isMatching(content)) {
return eCommand;
} else if (fCommand.isMatching(content)) {
return fCommand;
} else {
return null;
}
}
In isMatching() method there are different regex'es and I try to figure out how this incoming String should be processed.
I am looking for a cleaner way to get rid of these sequential if statements. Because whenever I create a new class into this factory I add another if statement.
Maybe Stream can help?
Stream<Command> stream = Stream.of(aCommand, bCommand, cCommand ...);
return stream.filter(x -> x.isMatching(content)).findFirst().orElse(null);
Now every time you add a new class, you just add a new object to the first line.
If you want to get rid of the sequential if statements you can use streams (like user Sweeper suggested) or loops and I would also suggest to return and optional which makes null handling clearer for the client.
Here are two suggested options to get rid of if else repetitions one with loops another with streams:
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
public class CommandPatternExample {
private List<Command> candidates = Arrays.asList(new ACommand(), new BCommand(), new CCommand());
public Optional<Command> createCommand(String content) {
for(Command command : candidates) {
if(command.isMatching(content)) {
return Optional.of(command);
}
}
return Optional.empty();
}
public Optional<Command> createCommandStream(String content) {
return candidates.stream().filter(c -> c.isMatching(content)).findFirst();
}
}
interface Command<T> {
void execute(T obj);
boolean isMatching(String s);
}
class ACommand implements Command<String> {
#Override
public void execute(String obj) {
}
#Override
public boolean isMatching(String s) {
return "A".equals(s);
}
}
class BCommand implements Command<String> {
#Override
public void execute(String obj) {
}
#Override
public boolean isMatching(String s) {
return "B".equals(s);
}
}
class CCommand implements Command<String> {
#Override
public void execute(String obj) {
}
#Override
public boolean isMatching(String s) {
return "C".equals(s);
}
}
Map might be a good idea. Meaning if you place your command instances into a map as values where your key would be something that you could match against incoming String. Then instead of sequential search with Efficiency O(n) you can get much better performance O(1). This is a short answer.
Besides that There is an open source java library MgntUtils (wriiten by me) that contains some utility called "Self-instantiating factories" Basically it manages and the Factory for you. All you will need to do is to create a class that implements a certain interface and the utility will add it for you into a map based factory. It might be useful to you. Here is the link to an article that explains about the utilities in the library as well as where to get the library (Github and Maven central). In the article look for the paragraph "Lifecycle management (Self-instantiating factories)". Also library comes with a detailed written javadoc and code example for that feature.
We have an exception Class A with a few fault codes defined as public static final and it is referenced in many files (more than 100) in our source code.
We want all these fault codes in Class B for some processing.
Currently we have implemented a method called getFaultCodes() in Class A to build a list of fault codes and return the same. The problem with this approach is that whenever an fault code is introduced, it has to be added in getFaultCode method as well. This is error prone, as a user may forget to add the new code to the method.
Moving these fault codes under an enum requires changes in many files all over the source code, so we don't want do this.
class ExceptionA {
public static final String faultCode1 = "CODE1";
public static final String faultCode2 = "CODE1";
public static final String faultCode3 = "CODE1";
List<String> getFaultCodes(){
list.add(faultCode1);
......
return list;
}
}
We are thinking about using reflection, but I'm posting in this forum just to check if there is a better solution. Please provide your suggestion to solve this problem.
Maybe you can go through an interface:
public interface FaultCodeProvider
{
String getFaultCode();
}
Then have your enums implement it:
public enum DefaultFaultCodes
implements FaultCodeProvider
{
FAULT1("text for fault 1"),
// etc
;
private final String value;
DefaultFaultCodes(final String value)
{
this.value = value;
}
#Override
public String getFaultCode()
{
return value;
}
}
Collecting them from the enum is then as easy as cycling through the enum's values().
I have modified code code like below:
class ExceptionA {
public enum codes {
CODE1("CODE1"),
CODE2("CODE2"),
CODE3("CODE3"),
private String code;
codes(String code){
this.code = code;
}
public String getCode() {
return this.code;
}
}
public static final String faultCode1 = code.CODE1;
public static final String faultCode2 = code.CODE2;
public static final String faultCode3 = code.CODE3;
}
So that I need not to change the variables occurrences "faultCode" in the source code, I can access the list of fault codes from other class.
While learning object oriented design I'm judging my own design critically. This framework should be able to print objects in either XML, or JSON, I've stubbed in a basic implementation to avoid getting into details of XML and Json parser apis for now.
So I made the Formatter be the base class. But with my current design, all derivatives of this base class would need to know that they have to call: getFormattedValue() to get output. Also I don't feel comfortable with all of those if else statements in the Formatter constructor. The clients would need to know to pass in either an "xml" or "json" in all derivatives of this class. How can I improve this design to conform to all Object oriented design Principles? Thanks in advance..
public class Formatter {
private String output;
public Formatter(Object object, String formatType){
if(formatType.equals("xml")){
output = getXMLFormat(object);
} else if(formatType.equals("json")) {
output = getJSONFormat(object);
}
}
private String getXMLFormat(Object object){
return "<title>"+object.toString()+"<title>"; // simplified
}
private String getJSONFormat(Object object){
return "{"+object.toString()+"}"; // simplified
}
protected String getFormattedValue(){
return output;
}
}
The derivative class:
public class ItemFormatter extends Formatter {
public ItemFormatter(Employee item, String formatOutput) {
super(item, formatOutput);
}
public void printItem(){
System.out.println(getFormattedValue());
}
}
Split the formatting into multiple classes/interfaces and use a Factory/Factory method in order to get the appropriate formatter. It could look something like this:
public interface Formatter {
String getFormattedValue();
}
and implement a JSonFormatter:
public class JSonFormatter implements Formatter {
String getFormattedValue(Object object) {
return "{"+object.toString()+"}";
}
}
get the correct formatter:
public class FormatterFactory {
public static Formatter getFormatter(String type) { // maybe use enum to decide
if (type.equals("json") {
return new JSonFormatter();
} else if (type.equals("xml")) {
return new XMLFormatter();
}
return new DefaultFormatter(); // returns toString for example
}
}
and finally usage:
String formattedXML = FormatterFactory.getFormatter("xml").getFormattedValue("foobar");
I can't recommend anything for getFormattedValue(), you can probably change the method name to make it more obvious, but that's about it.
With regards to the xml and json, you can probably use Enums.
public Enum EnumFormatType {
FORMAT_XML, FORMAT_JSON;
}
public Formatter(Object object, EnumFormatType formatType) {
if(EnumFormatType.FORMAT_XML.equals(formatType)){
// etc...
}
}
I would start by providing a abstract class to format.
abstract class Formatter {
String format(Object o);
}
Then we specialize two Formatter for XML and JASON
class XMLFormatter extends Formatter {
String format(Object o) {
return "<title>"+o.toString()+"<title>";
}
}
Now you just have to choose which formater you need and just call format on any of them to get the right string.
I think the below code looks more extensible.
public interface IFormatter
{
String GetFormatted(Object object);
}
public class JSonFormatter extends IFormatter
{
public String GetFormatted(Object object)
{
return "{"+object.toString()+"}";
}
}
public class XMLFormatter extends IFormatter
{
public String GetFormatted(Object object)
{
return "<title>"+object.toString()+"<title>";
}
}
public class ItemFormatter
{
public void printItem(Employee item, IFormatter formatter)
{
System.out.println(formatter.GetFormatted(item));
}
}
And it can be called like
itemFormatterInsatnce.printItem(empInstance, formatterInstance);
Also the formatter instance can be resolved using a formatterFactory either through code or configuration.