I changed a class that implements a superclass interface that now looks like:
class TimestampConversion(format: String, formatter: SimpleDateFormat) extends ObjectConversion[Any] {
override def execute(input: String): Timestamp = {
// hidden implementation details
}
override def revert(input: Any): String = {
// hidden implementation details
}
override def fromString(input: String): Timestamp = {
// hidden implementation details
}
}
object TimestampConversion {
def apply(format: String): Try[TimestampConversion] = {
// hidden implementation details
new SimpleDateFormat().map(new TimestampConversion(format, _))
}
}
After I changed the code, I started getting cast exceptions when calling this class. This class used to work when it was:
class TimestampConversion(format: String, formatter: SimpleDateFormat) extends ObjectConversion[Any] with FormattedConversion[SimpleDateFormat] {
def this(format: String) = this(format, new SimpleDateFormat(format))
override def execute(input: String): Timestamp = {
// hidden implementation details
}
override def revert(input: Any): String = {
// hidden implementation details
}
override def fromString(input: String): Timestamp = {
// hidden implementation details
}
override def getFormatterObjects: Array[SimpleDateFormat] = {
// hidden implementation details
}
}
The hierarchy of subclasses is TimestampConversion(sub) <-- ObjectConversion <-- NullConversion (super)
When I try calling the calling my newly modified TimestampConversion class, I get this exception
java.lang.ClassCastException:
...TimestampConversion cannot be cast to
...NullConversion
at...my_parser$$anonfun$7.apply(my_parser.scala:65)
at ...my_parser$$anonfun$7.apply(my_parser.scala:59)
where TimestampConversion is called here:
for ((col, i) <- all_cols) {
val converter = col.type match {
// hidden implementation details
case TimestampType => TimestampConversion("some_format") // line 65 in my_parser
case unknown => throw new RuntimeException("Met a bad type")
}
}
and it used to be called like this (when it was working):
for ((col, i) <- all_cols) {
val converter = col.type match {
// hidden implementation details
case TimestampType => new TimestampConversion("some_format")
case unknown => throw new RuntimeException("Met a bad type")
}
}
I've implemented the two #Override methods from the NullConversion interface, and I don't get a warning or anything from my IDE before compiling saying that TimestampConversion isn't fully implementing NullConversion or something. I merely got rid of the association with FormattedConversion. Why am I not able to invoke my class like this? I've also never touched the ObjectConversion and NullConversion classes.
Here are the superclasses' structures:
public abstract class ObjectConversion<T> extends NullConversion<String, T> {
public ObjectConversion() {
super(null, null);
}
public ObjectConversion(T val, String nullVal) {
super(val, nullVal);
}
#Override
public T execute(String input) {
return super.execute(input);
}
protected final T fromInput(String input) {
return fromString(input);
}
protected abstract T fromString(String input);
#Override
public String revert(T input) {
return super.revert(input);
}
#Override
protected final String undo(T input) {
// hidden implementation details
}
public T getValueIfStringIsNull() {
// hidden implementation details
}
public String getValueIfObjectIsNull() {
// hidden implementation details
}
public void setValueIfStringIsNull(T valueIfStringIsNull) {
// hidden implementation details
}
public void setValueIfObjectIsNull(String valueIfObjectIsNull) {
// hidden implementation details
}
}
and this class extends NullConversion<String, T>
public abstract class NullConversion<I, O> implements Conversion<I, O> {
private O valueOnNullInput;
private I valueOnNullOutput;
public NullConversion() {
this(null, null);
}
public NullConversion(O valueOnNullInput, I valueOnNullOutput) {
// hidden implementation details
}
#Override
public O execute(I input) {
// hidden implementation details
}
protected abstract O fromInput(I input);
#Override
public I revert(O input) {
// hidden implementation details
}
protected abstract I undo(O input);
public O getValueOnNullInput() {
// hidden implementation details
}
public I getValueOnNullOutput() {
// hidden implementation details
}
public void setValueOnNullInput(O valueOnNullInput) {
// hidden implementation details
}
public void setValueOnNullOutput(I valueOnNullOutput) {
// hidden implementation details
}
}
Also, here's the class that the old code used to extend FormattedConversion (though I doubt it makes a difference)
public interface FormattedConversion<T> {
T[] getFormatterObjects();
}
Related
I am designing a validation module. It has 100 error codes(i.e. errcd_01, errcd_02,..,errcd_100) to be validated. In input I am getting a specific error code(i.e. errcd_01) out of above 100.
Module should perform validation for that specific error code.
I am using factory pattern.
/* Interface */
public interface validateErrCd {
void check_errcd();
}
/* Concrete classes implementing the same interface */
public class validateErrCd_01 implements validateErrCd {
#Override
public void check_errcd() {
//business logic related to errcd_01
}
}
public class validateErrCd_02 implements validateErrCd {
#Override
public void check_errcd() {
//business logic related to errcd_02
}
}
.
.
.
public class validateErrCd_100 implements validateErrCd {
#Override
public void check_errcd() {
//business logic related to errcd_100
}
}
/* Factory */
public class ErrorValidationFactory {
//use check_errcd method to get object of type shape
public validateErrCd getValidation(String errorCode){
if(errorCode == null){
return null;
}
if(errorCode.equalsIgnoreCase("errcd_01")){
return new validateErrCd_01();
} else if(errorCode.equalsIgnoreCase("errcd_02")){
return new validateErrCd_02();
} ..
.......
else if(errorCode.equalsIgnoreCase("errcd_100")){
return new validateErrCd_100();
}
else {
return null;
}
}
}
/* I am using the Factory to get object of concrete class by passing an specific error code to be validated (i.e. "errcd_01"). */
public class FactoryPatternDemo {
public static void main(String[] args) {
ErrorValidationFactory errorFactory = new ErrorValidationFactory();
//get an object of validateErrCd_01 and call its check_errcd method.
validateErrCd errcd01 = errorFactory.getValidation("errcd_01");
//call check_errcd method of validateErrCd_01
errcd01.check_errcd();
}
}
Now due to multiple if/else inside Factory class ErrorValidationFactory, I am getting couple of CI/CD errors while performing mvn clean install.
e.g. [MethodLength] - checkstyle, Rule:CyclomaticComplexity - PMD.
So is there a way I can replace if/else, switch case kind of decision making inside factory which does not trigger above CI/CD errors in Java?
Note : If possible I would like to avoid reflection
You could use a Map:
public class ErrorValidationFactory {
private Map<String,Supplier<validateErrCd>> creators=new HashMap<>();
public ErrorValidationFactory(){
creators.put("errcd_100",validateErrCd_100::new);
//Same for others
}
//use check_errcd method to get object of type shape
public validateErrCd getValidation(String errorCode){
if(errorCode == null){
return null;
}
return creators.getOrDefault(errorCode,()->null);
}
}
Supplier is a functional interface that contains a method returning an object. SomeClass::new or ()->new SomeClass() means that the constructor of the class will be used for that.
This allows to to create the instances later.
If you want to create the Map only once, you can make it static and populate it in a static initializer.
However, if you really want to dynamically get the constructors, you would need to use reflection.
I'm having some trouble when trying to translate Java code with nested generics to Kotlin. Take this Java SSCCE as an example (please note the relation between S and T):
public class JavaTest {
private class JavaObjectContainer<S> {
public S obj;
}
private abstract class JavaSampleClass<S, T extends JavaObjectContainer<S>> {
private Class<S> type;
public JavaSampleClass(Class<S> type) {
this.type = type;
}
public Class<S> getType() {
return type;
}
public abstract void callMethod(S s);
}
private class JavaChildSampleClass extends JavaSampleClass<String, JavaObjectContainer<String>> {
public JavaChildSampleClass() {
super(String.class);
}
#Override
public void callMethod(String s) {}
}
private class JavaTestContainer {
private Map<Class<?>, JavaSampleClass> sampleClasses;
public JavaTestContainer() {
this.sampleClasses = new HashMap<>();
}
public void registerJavaSampleClass(JavaSampleClass javaSampleClass) {
sampleClasses.put(javaSampleClass.getType(), javaSampleClass);
}
public void callMethod(Object obj) {
sampleClasses.get(obj.getClass()).callMethod(obj);
}
}
public void test() {
JavaTestContainer javaTestContainer = new JavaTestContainer();
javaTestContainer.registerJavaSampleClass(new JavaChildSampleClass());
javaTestContainer.callMethod("Hola");
}
}
Think of this SSCCE as an implementation of a generic factory pattern, where the user registers multiple JavaSampleClass whose methods can be invoked in the future.
As Kotlin does not provide an alternative to wildcards, I have tried the following approach:
class KotlinTest {
private class KotlinObjectContainer<S> {
var obj : S? = null
}
private open class KotlinSampleClass<S, T : KotlinObjectContainer<S>>(var type: Class<S>) {
fun callMethod(s : S) {}
}
private class KotlinChildSampleClass : KotlinSampleClass<String, KotlinObjectContainer<String>>(String::class.java)
private inner class KotlinTestContainer {
private val sampleClasses: MutableMap<Class<Any>, KotlinSampleClass<Any, KotlinObjectContainer<Any>>> = mutableMapOf()
fun registerKotlinSampleClass(kotlinSampleClass: KotlinSampleClass<Any, KotlinObjectContainer<Any>>) {
sampleClasses.put(kotlinSampleClass.type, kotlinSampleClass)
}
fun callMethod(obj : Any) {
sampleClasses[obj.javaClass]?.callMethod(obj)
}
}
fun test() {
val kotlinTestContainer = KotlinTestContainer()
// Exception!
kotlinTestContainer.registerKotlinSampleClass(KotlinChildSampleClass())
kotlinTestContainer.callMethod("Hello")
}
}
The above code throws the following exception in the IDE:
Type mismatch.
Required: KotlinTest.KotlinSampleClass<Any, KotlinObjectContainer<Any>>
Found: KotlinTest.KotlinChildSampleClass
I have been thinking of declaring sampleClasses map as
MutableMap<*, *>
But then, how can I initialize it? Also, as * represents an out-projected parameter, the IDE shows me an error when trying to put new values in the map.
How can I overcome this issue? I'm quite certain that I'm missing something...
As Kotlin does not provide an alternative to wildcards...
I have been thinking of declaring sampleClasses map as
MutableMap<*, *>
For this case * corresponds to wildcards perfectly well. If you have Class<?> in Java, you want Class<*> in Kotlin, not Class<Any> or *.
private val sampleClasses: MutableMap<Class<*>, KotlinSampleClass<*, *>> = mutableMapOf()
fun registerKotlinSampleClass(kotlinSampleClass: KotlinSampleClass<*, *>) {
sampleClasses.put(kotlinSampleClass.type, kotlinSampleClass)
}
#Suppress("UNCHECKED_CAST")
fun callMethod(obj : Any) {
(sampleClasses[obj.javaClass] as KotlinSampleClass<Any, *>?)?.callMethod(obj)
}
The only reason you don't need the cast in callMethod in Java is because you are using raw types (as Turing85's comment mentions) and the compiler basically gives up on type checking.
I would like to store some field of type ParentClass as json string into my database. I don't want to use Serializable interface and DataType.SERIALIZABLE cause it ties with full class name of serialized class.
So I'm using the following code:
class ParentClass {
#DatabaseField(persisterClass = MyFieldClassPersister.class)
private MyFieldClass myField;
}
where persister class a kind of:
public class MyFieldClassPersister extends StringType {
private static final MyFieldClassPersister singleTon = new MyFieldClassPersister();
public static MyFieldClassPersister getSingleton() {
return singleTon;
}
protected MyFieldClassPersister() {
super(SqlType.STRING, new Class<?>[0]);
}
#Override
public Object parseDefaultString(FieldType fieldType, String defaultStr) {
return jsonStringToObject(defaultStr);
}
#Override
public Object resultToSqlArg(FieldType fieldType, DatabaseResults results, int columnPos) throws SQLException {
String string = results.getString(columnPos);
return jsonStringToObject(string);
}
private static MyFieldClass jsonStringToObject(String string) {
// json to object conversion logic
}
}
Here are two issues I've met:
I didn't get how to specify custom convertion from object to string. Seems that ORMLite calls Object.toString() in order to get string representation of the object. It would be great to have some method in Persister in which I could specify how to convert Object to string (json in my case). Yes, I can override toString() method in MyFieldClass, but it is more convenient to perform conversion in Persister. Is there any method I could override in order to specify convertion from model object to db-object?
If I mark my custom field type as String type:
class ParentClass {
#DatabaseField(dataType = DataType.STRING, persisterClass = MyFieldClassPersister.class)
private MyFieldClass myField;
}
then ormlite crashes when saving object with the following message:
java.lang.IllegalArgumentException: Field class com.myapp.venue.MyFieldClass for
field FieldType:name=myField,class=ParentClass is not valid for type
com.j256.ormlite.field.types.StringType#272ed83b, maybe should be
class java.lang.String
It doesn't crash if I omit dataType specification. Can I avoid this crash in some way? It seems to me that it's better to specify types explicitly.
So basically your persister should be implemented in the next way:
public class MyFieldClassPersister extends StringType {
private static final MyFieldClassPersister INSTANCE = new MyFieldClassPersister();
private MyFieldClassPersister() {
super(SqlType.STRING, new Class<?>[] { MyFieldClass.class });
}
public static MyFieldClassPersister getSingleton() {
return INSTANCE;
}
#Override
public Object javaToSqlArg(FieldType fieldType, Object javaObject) {
MyFieldClass myFieldClass = (MyFieldClass) javaObject;
return myFieldClass != null ? getJsonFromMyFieldClass(myFieldClass) : null;
}
#Override
public Object sqlArgToJava(FieldType fieldType, Object sqlArg, int columnPos) {
return sqlArg != null ? getMyFieldClassFromJson((String) sqlArg) : null;
}
private String getJsonFromMyFieldClass(MyFieldClass myFieldClass) {
// logic here
}
private MyFieldClass getMyFieldClassFromJson(String json) {
// logic here
}
}
You should register it in onCreate method of your OrmLiteSqliteOpenHelper class
#Override
public void onCreate(SQLiteDatabaseHolder holder, ConnectionSource connectionSource) {
try {
//...
DataPersisterManager
.registerDataPersisters(MyFieldClassPersister.getSingleton());
} catch (SQLException e) {
// log exception
}
}
And then you can use it in your model like this:
#DatabaseField(persisterClass = MyFieldClassPersister.class, columnName = "column_name")
protected MyFieldClass myFieldClass;
Don't register the persister adapter in the onCreate() method. This method only gets called when your database is first created. You should add this somewhere else, like your constructor or onOpen() method.
Is there a way for me to get a super implementation directly through getContructor? I want to call the constructor on "this class or any superclass".
The scenario details are that I have a base class that builds its data using reflection but the data is coming in from an external file. The external loader has a lookup that checks to see if data exists for a particular class and all of that is wrapped into ImplementedCard, below.
This works fine (enough) and isn't directly related to the question aside from my needing to be able to create all of these instances starting from an ImplementedCard instance:
public class Card implements DeepCopyable<Card> {
protected ImplementedCardList.ImplementedCard implementedCard;
public Card() {
this.implementedCard = ImplementedCardList.getInstance().getCardForClass(this.getClass());
this.initFromImplementedCard(this.implementedCard);
}
public Card(ImplementedCardList.ImplementedCard implementedCard) {
this.implementedCard = implementedCard;
this.initFromImplementedCard(this.implementedCard);
}
public void initFromImplementedCard(ImplementedCardList.ImplementedCard implementedCard) {
if (implementedCard != null) {
this.name_ = implementedCard.name_;
/* ... and so on */
}
}
// This deepCopy pattern is required because we use the class of each card to recreate it under certain circumstances
#Override
public Card deepCopy() {
Card copy = null;
try {
try {
copy = this.getClass().getConstructor(ImplementedCardList.ImplementedCard.class).newInstance(this.implementedCard);
} catch(NoSuchMethodException e) {
if(!this.getClass().equals(TestHero.class)) {
log.warn(this.getClass().toString() + " is missing ImplementedCard constructor");
}
copy = getClass().newInstance();
} catch(InvocationTargetException e) {
log.error("InvocationTargetException error", e);
copy = getClass().newInstance();
}
} catch(InstantiationException e) {
log.error("instantiation error", e);
} catch(IllegalAccessException e) {
log.error("illegal access error", e);
}
if (copy == null) {
throw new RuntimeException("unable to instantiate card.");
}
copy.name_ = this.name_;
/* ... and so on */
return copy;
}
}
This base class is then extended like so:
public class Minion extends Card implements CardEndTurnInterface, CardStartTurnInterface {
public Minion() {
super();
}
public Minion(ImplementedCardList.ImplementedCard implementedCard) {
super(implementedCard);
}
#Override
public void initFromImplementedCard(ImplementedCardList.ImplementedCard implementedCard) {
if (implementedCard != null) {
super.initFromImplementedCard(implementedCard);
/* custom init goes here */
}
}
/* other class details follow */
}
public abstract class Hero extends Minion implements MinionSummonedInterface {
public Hero() {
super();
}
public Hero(ImplementedCardList.ImplementedCard implementedCard) {
super(implementedCard);
}
/* no custom init; other class details follow */
}
public class Hunter extends Hero {
public Hunter() {
super();
}
public Hunter(ImplementedCardList.ImplementedCard implementedCard) {
super(implementedCard);
}
/* no custom init; other class details follow */
}
This goes on for hundreds of classes. What I want to do is pull out the constructors that do nothing but call super with the same parameters but when I do, it breaks the getConstructor call in deepCopy.
For each class, you can do:
Hero h = new Hero();
Class hc = h.getClass();
// Get super class and its constructor.
Class<?> sc = hc.getSuperclass();
Constructor scConst = sc.getConstructor(ImplementedCard.class);
// Get super class's parent and its constructor.
Class<?> ssc = sc.getSuperclass();
Constructor sscConst = ssc.getConstructor(ImplementedCard.class);
You could also put this in a loop until you get to Object.class or some other point in the class hierarchy where you'd like to break.
As #nhylated suggested, try
this.getClass().getSuperClass()
Here is a nice explanation regarding why
super.getClass()
behaves like it does.
I have to create a list of objects, which are configured according to the name of some classes received as input.
For each object I have to call a method, which add an operation that is created dynamically.
However I don't know exactly ho to resolve the problem.
Please see an example below.
String className; // this is an input parameter
final Class<?> classType = Class.forName(className);
// here I would like to use classType instead of "?" but it gives me an error.
Task<?> task = TaskFactory.createTask((String)classType.getField("_TYPE").get(null)));
tasks.put(task, null);
task.addOperation(new Operation<classType>() { // this gives an error
#Override
public void onNewInput(classType input) { // this gives an error
System.out.println(input)
}
});
As you can see from the comments, the surrounding infrastructure and the intention are not entirely clear. However, you can achieve a certain degree of type-safety with a "helper" method that captures the type of the given Task, and allows you to work with this type internally:
public class RuntimeType
{
public static void main(String[] args) throws Exception
{
String className = "";
final Class<?> classType = Class.forName(className);
Task<?> task = TaskFactory.createTask((String)classType.getField("_TYPE").get(null));
addOperation(task);
}
private static <T> void addOperation(Task<T> task)
{
task.addOperation(new Operation<T>()
{
#Override
public void onNewInput(T input)
{
System.out.println(input);
}
});
}
}
class TaskFactory
{
public static Task<?> createTask(String string)
{
return null;
}
}
class Task<T>
{
public void addOperation(Operation<T> operation)
{
}
}
interface Operation<T>
{
void onNewInput(T input);
}