Is there a native way in kotlin to access a nested complex object (parsed from JSON string) through a variable?
Smth similar to:
var = "Obj4"
a = Obj1.Obj2.Obj3.$var.Obj5.Array[index]
Thanks a lot in advance
Taken from here
Using the reflection. Don't forget to add the dependency.
Global inline extension fun for Any:
inline fun <reified T : Any> Any.getThroughReflection(propertyName: String): T? {
val getterName = "get" + propertyName.capitalize()
return try {
javaClass.getMethod(getterName).invoke(this) as? T
} catch (e: NoSuchMethodException) {
null
}
}
Related
I want to fix the errors, which sometimes happened in my app:
ERROR: invalid byte sequence for encoding "UTF8": 0x00; nested exception is org.postgresql.util.PSQLException: ERROR: invalid byte sequence for encoding "UTF8": 0x00
I think right way to solve it is to sanitize all text fields before insertion to database with
this.replace("\\u0000", "")
The question is how to implement the converter or custom binding in one place to force JOOQ invoke this replace function?
Using jOOQ's Converter or Binding
I'm assuming this is about JSON and PostgreSQL? See also: org.jooq.exception.DataAccessException: unsupported Unicode escape sequence \u0000
It seems that a Converter<JSON, JSON> (or JSONB, respectively) would suffice?
Converter.ofNullable(JSON.class, JSON.class,
j -> j,
j -> JSON.json(j.data().replace("\\u0000", ""))
);
And then, attach that everywhere using a forcedType:
<configuration xmlns="http://www.jooq.org/xsd/jooq-codegen-3.17.0.xsd">
<generator>
<database>
<forcedTypes>
<forcedType>
<userType>org.jooq.JSON</userType>
<converter>Converter.ofNullable(JSON.class, JSON.class,
j -> j,
j -> JSON.json(j.data().replace("\\u0000", ""))
)</converter>
<includeTypes>(?i:json)</includeTypes>
</forcedType>
</forcedTypes>
</database>
</generator>
</configuration>
Using JDBC
You could, of course, also just proxy JDBC and patch PreparedStatement::setString:
#Override
public void setString(int parameterIndex, String x) throws SQLException {
if (x == null)
delegate.setString(parameterIndex, x);
else
delegate.setString(parameterIndex, x.replace("\\u0000", "");
}
// Also all the other methods that might accept strings
A simple way to approach this is by using jOOQ's own JDBC proxy utility types, to avoid implementing the entire JDBC API:
org.jooq.tools.jdbc.DefaultConnection
org.jooq.tools.jdbc.DefaultPreparedStatement
This will handle things on a lower level, including when you don't use jOOQ. However, if you're using inline values, then those won't be converted by this approach, as those values are transparent to JDBC
So what I've did to solve the problem:
Added custom binding:
class PostgresStringsBinding : Binding<String, String> {
override fun converter(): Converter<String, String> {
return object : Converter<String, String> {
override fun from(dbString: String?): String? {
return dbString
}
override fun to(string: String?): String? {
return string?.withEscapedNullChars()
}
override fun fromType(): Class<String> {
return String::class.java
}
override fun toType(): Class<String> {
return String::class.java
}
}
}
#Throws(SQLException::class)
override fun sql(ctx: BindingSQLContext<String>) {
if (ctx.render().paramType() == ParamType.INLINED) ctx.render()
.visit(DSL.inline(ctx.convert(converter()).value())).sql("::text") else ctx.render().sql("?::text")
}
#Throws(SQLException::class)
override fun register(ctx: BindingRegisterContext<String>) {
ctx.statement().registerOutParameter(ctx.index(), Types.VARCHAR)
}
#Throws(SQLException::class)
override fun set(ctx: BindingSetStatementContext<String>) {
ctx.statement().setString(ctx.index(), Objects.toString(ctx.convert(converter()).value(), null))
}
#Throws(SQLException::class)
override fun get(ctx: BindingGetResultSetContext<String>) {
ctx.convert(converter()).value(ctx.resultSet().getString(ctx.index()))
}
#Throws(SQLException::class)
override fun get(ctx: BindingGetStatementContext<String>) {
ctx.convert(converter()).value(ctx.statement().getString(ctx.index()))
}
#Throws(SQLException::class)
override fun set(ctx: BindingSetSQLOutputContext<String>) {
throw SQLFeatureNotSupportedException()
}
#Throws(SQLException::class)
override fun get(ctx: BindingGetSQLInputContext<String>) {
throw SQLFeatureNotSupportedException()
}
}
and registered it as ForcedType:
ForcedType()
.withUserType("java.lang.String")
.withBinding("org.example.jooqbindings.PostgresStringsBinding")
.withIncludeExpression(".*")
.withIncludeTypes("VARCHAR|TEXT")
I have two different pieces of code. In one i need to use object and in the second i'm not.
Can someone explain me the difference between the situation:
first Code:
private val onInitWebResponseHandler: VolleyHandler.WebResponseHandler = VolleyHandler.WebResponseHandler()
{
Thread(ParseJsonStringOnInit(WeakReference(this),
weakRefIOnAllScoresDataFirstFetched, it)).start()
}
Second Code:
val competitionOrderLevelComparator : Comparator<CompetitionObj> = object : Comparator<CompetitionObj> {
override fun compare(object1: CompetitionObj, object2: CompetitionObj): Int
{
return object1.orderLevel - object2.orderLevel
}
}
fun interface WebResponseHandler
{
fun onWebResponseFinished(jsonString:String?)
}
In addition how the first code, we can have () brackets if interface doesn't have a constructor?
I'm trying to read a list of string from a file, which is structured as a list:
ElemA
ElemB
ElemC
I need to save into this variable, which is defined as:
private var history: Array<out String>?
I made this method, but it doesn't works because it requires an Array? as output, but it founds an Array<(out) Any!>!
private fun loadHistory(): Array<out String>? {
val list = ArrayList<String>()
File("history").forEachLine { list.add(it) }
return list.toArray()
}
How can I solve?
As suggested by #jsamol in the comments.
You should use toTypedArray() instead of toArray() to get an array of the specific type.(ref)
toArray() returns new array of type Array<Any?>. (ref)
private fun loadHistory(): Array<out String>? {
val list = ArrayList<String>()
File("history").forEachLine { list.add(it) }
return list.toTypedArray()
}
I am trying to dynamically create a class instance based type using generics, however I am encountering difficulty with class introspection.
Here are the questions:
Is there a Swift-equivalent to Obj-C's self.class?
Is there a way to instantiate a class using the AnyClass result from NSClassFromString?
Is there a way to get AnyClass or otherwise type information strictly from a generic parameter T? (Similar to C#'s typeof(T) syntax)
Well, for one, the Swift equivalent of [NSString class] is .self (see Metatype docs, though they're pretty thin).
In fact, NSString.class doesn't even work! You have to use NSString.self.
let s = NSString.self
var str = s()
str = "asdf"
Similarly, with a swift class I tried...
class MyClass {
}
let MyClassRef = MyClass.self
// ERROR :(
let my_obj = MyClassRef()
Hmm… the error says:
Playground execution failed: error: :16:1: error: constructing an object of class type 'X' with a metatype value requires an '#required' initializer
Y().me()
^
<REPL>:3:7: note: selected implicit initializer with type '()'
class X {
^
It took me a while to figure out what this means… turns out it wants the class to have a #required init()
class X {
func me() {
println("asdf")
}
required init () {
}
}
let Y = X.self
// prints "asdf"
Y().me()
Some of the docs refer to this as .Type, but MyClass.Type gives me an error in the playground.
Here's how to use NSClassFromString. You have to know the superclass of what you're going to end up with. Here are a superclass-subclass pair that know how to describe themselves for println:
#objc(Zilk) class Zilk : NSObject {
override var description : String {return "I am a Zilk"}
}
#objc(Zork) class Zork : Zilk {
override var description : String {return "I am a Zork"}
}
Notice the use of the special #obj syntax to dictate the Objective-C munged name of these classes; that's crucial, because otherwise we don't know the munged string that designates each class.
Now we can use NSClassFromString to make the Zork class or the Zilk class, because we know we can type it as an NSObject and not crash later:
let aClass = NSClassFromString("Zork") as NSObject.Type
let anObject = aClass()
println(anObject) // "I am a Zork"
And it's reversible; println(NSStringFromClass(anObject.dynamicType)) also works.
Modern version:
if let aClass = NSClassFromString("Zork") as? NSObject.Type {
let anObject = aClass.init()
print(anObject) // "I am a Zork"
print(NSStringFromClass(type(of:anObject))) // Zork
}
If I'm reading the documentation right, if you deal with instances and e.g. want to return a new instance of the same Type than the object you have been given and the Type can be constructed with an init() you can do:
let typeOfObject = aGivenObject.dynamicType
var freshInstance = typeOfObject()
I quickly tested it with String:
let someType = "Fooo".dynamicType
let emptyString = someType()
let threeString = someType("Three")
which worked fine.
In swift 3
object.dynamicType
is deprecated.
Instead use:
type(of:object)
Swift implementation of comparing types
protocol Decoratable{}
class A:Decoratable{}
class B:Decoratable{}
let object:AnyObject = A()
object.dynamicType is A.Type//true
object.dynamicType is B.Type//false
object.dynamicType is Decoratable.Type//true
NOTE: Notice that it also works with protocols the object may or may not extend
Finally got something to work. Its a bit lazy but even the NSClassFromString() route did not work for me...
import Foundation
var classMap = Dictionary<String, AnyObject>()
func mapClass(name: String, constructor: AnyObject) -> ()
{
classMap[name] = constructor;
}
class Factory
{
class func create(className: String) -> AnyObject?
{
var something : AnyObject?
var template : FactoryObject? = classMap[className] as? FactoryObject
if (template)
{
let somethingElse : FactoryObject = template!.dynamicType()
return somethingElse
}
return nil
}
}
import ObjectiveC
class FactoryObject : NSObject
{
#required init() {}
//...
}
class Foo : FactoryObject
{
class override func initialize()
{
mapClass("LocalData", LocalData())
}
init () { super.init() }
}
var makeFoo : AnyObject? = Factory.create("Foo")
and bingo, "makeFoo" contains a Foo instance.
The downside is your classes must derrive from FactoryObject and they MUST have the Obj-C +initialize method so your class gets automagically inserted in the class map by global function "mapClass".
Here is another example showing class hierarchy implementation, similar to accepted answer, updated for the first release of Swift.
class NamedItem : NSObject {
func display() {
println("display")
}
required override init() {
super.init()
println("base")
}
}
class File : NamedItem {
required init() {
super.init()
println("folder")
}
}
class Folder : NamedItem {
required init() {
super.init()
println("file")
}
}
let y = Folder.self
y().display()
let z = File.self
z().display()
Prints this result:
base
file
display
base
folder
display
I'm going to internationalize groovy API abit.
For final class (e.g. String)
String.metaClass.вСтроку = {-> this.toString() }
However, this will create additional closure. Isn't there any way to just alias method with another method?
Something like this:
String.metaClass.вСтроку = String.metaClass.&toString
You could use #Category transform like this
#Category(String) class StringInternationalization {
String вСтроку() {
this.toString()
}
int длина() {
this.length()
}
}
class ApplyMixin {
static {
String.mixin(StringInternationalization)
final helloString = "Привет мир!"
println helloString.вСтроку()
assert helloString.длина() == helloString.length()
}
}
new Main()
This will create 1 Category class for each localised class and one class to apply all mixin transformations(to register all methods.) Also should be faster, then individual closures.
More reading here: http://groovy.codehaus.org/Category+and+Mixin+transformations