I'm fairly new to Kryo so forgive me if I've made a silly mistake.... I have read the manual, and I think I understand generally how Kryo serializes, but I'm having trouble deserializing a JComboBox.
First, I tried this:
Kryo kryo = new Kryo();
Output output = new Output(new FileOutputStream("/tempTest/newTest.kr"));
JComboBox objectToWrite = new JComboBox();
kryo.writeObject(output, objectToWrite);
output.flush();
output.close();
then read...
Input input = new Input(new FileInputStream("/tempTest/newTest.kr"));
JComboBox cbox = kryo.readObject(input, JComboBox.class);
Doing this generates a "missing no-arg constructor" exception. So I set the fallback instantiator strategy:
((DefaultInstantiatorStrategy) kryo.getInstantiatorStrategy()).setFallbackInstantiatorStrategy(new StdInstantiatorStrategy());
However, now I get this exception:
Exception in thread "main" java.lang.IllegalAccessError: tried to access method javax.swing.plaf.metal.MetalComboBoxButton.<init>()V from class javax.swing.plaf.metal.MetalComboBoxButtonConstructorAccess
at javax.swing.plaf.metal.MetalComboBoxButtonConstructorAccess.newInstance(Unknown Source)
at com.esotericsoftware.kryo.Kryo$DefaultInstantiatorStrategy$1.newInstance(Kryo.java:1193)
at com.esotericsoftware.kryo.Kryo.newInstance(Kryo.java:1061)
at com.esotericsoftware.kryo.serializers.FieldSerializer.create(FieldSerializer.java:547)
at com.esotericsoftware.kryo.serializers.FieldSerializer.read(FieldSerializer.java:523)
at com.esotericsoftware.kryo.Kryo.readClassAndObject(Kryo.java:761)
at com.esotericsoftware.kryo.serializers.CollectionSerializer.read(CollectionSerializer.java:116)
at com.esotericsoftware.kryo.serializers.CollectionSerializer.read(CollectionSerializer.java:22)
at com.esotericsoftware.kryo.Kryo.readObject(Kryo.java:679)
at com.esotericsoftware.kryo.serializers.ObjectField.read(ObjectField.java:106)
at com.esotericsoftware.kryo.serializers.FieldSerializer.read(FieldSerializer.java:528)
at com.esotericsoftware.kryo.Kryo.readObject(Kryo.java:657)
at T2SaveLoad.saveLoad(T2SaveLoad.java:112)
at T2SaveLoad.main(T2SaveLoad.java:40)
I'm not sure exactly what is happening, can anyone help?
Also, how is the instantiation strategy chosen by kryo? Does each serializer have a different instantiator strategy, or does kryo just have a default and a fallback for all objects it deserializes?
What if you do:
kryo.register(JComboBox.class, new JavaSerializer());
(which does in fact serialize/deserialize without any errors) - native java deserialization doesn't call the constructor (apart from the no-arg one in the first superclass that doesn't implement serializable), but if you haven't told kryo to set the instantiator strategy to StdInstantiatorStrategy(), does it still try to use a constructor? or does the fact that it is using its JavaSerializer make it use some other instantiation strategy? (which would perhaps make the instantiation strategy serializer-specific?
I hope this makes sense, please let me know if it doesn't!!
Related
I don't or can't modify the Java source code. The goal to configure just the Kotlin compiler to know what is nullable and what isn't.
You can specify the type manually if you know something will never be null. For example, if you have the following Java code:
public static Foo test() {
return null;
}
and you call it in Kotlin like this:
val result = Foo.test()
then result will have a type of Foo! by default – which means it can be either Foo or Foo?.. the compiler doesn't have enough information to determine that.
However, you can force the type manually:
val result: Foo = Foo.test()
// use "result" as a non-nullable type
Of course, if at runtime that is not true, you'll get a NullPointerException.
For reference, please check the documentation.
I don't know of a way to configure the compiler for this, but IntelliJ IDEA has a feature that allows you to add annotations to code via an XML file called external annotations.
You can add the Jetbrains #Nullable and #NotNull annotations to library code, but when I've tried it, it only results in compiler warnings rather than errors when you use incorrect nullability in your code. These same annotations generate compiler errors when used directly in the source code. I don't know why there is a difference in behavior.
You can use extension functions for this. If you have a method String foo() in the class Test, you can define the extension function
fun Test.safeFoo(): String = this.foo()!!
The advantage is that the code is pretty obious.
The disadvantage of this approach is that you need to write a lot of boiler plate code. You also have to define the extension function in a place where all your modules or projects can see it. Also, writing that much code just to avoid !! feels like overkill.
It should also be possible to write a Kotlin compiler extension which generates them for you but the extension would need to know which methods never return null.
I am using ByteBuddy to generate a class.
Prior to working with DynamicType.Builder, I was going to store a MethodCall as an instance variable:
private final MethodCall frobCall =
MethodCall.invoke(ElementMatchers.named("frob")); // here I invoke a method I'm going to define as part of the instrumented type
Then later in my generation logic for the instrumented type I define the frob method to do something:
.defineMethod("frob")
.intercept(...etc....) // here I define frob to do something
…and I define the (let's say) baz method to invoke frob:
.defineMethod("baz")
.withParameter(...) // etc.
.intercept(frobCall); // invokes "frob", which I've just defined above
(I am trying to keep this simple and may have mistyped something but I hope you can see the gist of what I'm trying to do.)
When I make() my DynamicType, I receive an error that indicates that the dynamic type does not define frob. This is mystifying to me, because of course I have defined it, as you can see above.
Is there some restriction I am unaware of that prohibits ElementMatchers from identifying instrumented type methods that are defined later? Do I really have to use MethodDescription.Latent here?
It should match all methods of the instrumented type. If this is not happening as expected, please set a breakpoint in MethodCall.MethodLocator.ForElementMatcher to see why the method is not showing up. I assume it is filtered by your method matcher.
I noticed however that it did not include private methods which is now fixed and will be released within Byte Buddy 1.10.18.
When using Mockito with Kotlin, if I try to verify Mock calls, it work fine like (this is in a Spring test):
#MockBean
lateinit var fragmentProcessor: FragmentProcessor
verify(fragmentProcessor, timeout(20000)).processFragment(expectedFragment)
that gives the expected behaviour... but just doing something like:
verify(fragmentProcessor, timeout(20000)).processFragment(Mockito.eq(expectedFragment))
will give the following error:
Missing method call for verify(mock) here:
-> at uk.co.argos.productapi.services.kafka.KafkaConsumerServiceTest.testFragmentProcessorReceivesMessages(KafkaConsumerServiceTest.kt:47)
Example of correct verification:
verify(mock).doSomething()
Also, this error might show up because you verify either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.
Mocking methods declared on non-public parent classes is not supported.
the same happens with ArgumentCaptor or other matchers
Are you sure that you call fragmentProcessor.processFragment(expectedFragment) somewhere in your code before verify times out?
Error message says that you don't, so verify throws an exception (as it should do).
In this line:
verify(fragmentProcessor, timeout(20000)).processFragment(expectedFragment)
You don't use verify correctly (you have to use Mockito.eq): it doesn't verify anything so doesn't throw, but it doesn't mean that it works as you suppose.
I am facing some very basic problem (that never faced in java before) and might be due my lack of knowledge in Kotlin.
I am currently trying to read a YML file. So Im doing it in this way:
private val factory = YamlConfigurationFactory(LinkedHashMap::class.java, validator, objectMapper, "dw")
Best on Dropwizard guide for configurations.
https://www.dropwizard.io/1.3.12/docs/manual/testing.html
So later in my function I do this"
val yml = File(Paths.get("config.yml").toUri())
var keyValues = factory.build(yml)
When using my debugger I can see there is a Map with key->values, just as it should be.
now when I do keyValues.get("my-key")
type inference failed. the value of the type parameter k should be mentioned in input types
Tried this but no luck
var keyValues = LinkedHashMap<String, Any>()
keyValues = factory.build(yml)
The YamlConfigurationFactory requires a class to map to, but I dont know if there is a more direct way to specify a Kotlin class than with the current solution +.kotlin, like
LinkedHashMap::class.java.kotlin
Here it also throws an error.
Ideas?
Well, this is a typical problem with JVM generics. Class<LinkedHashMap> carries no info on what are the actual types of its keys and values, so the keyValues variable always ends up with the type LinkedHashMap<*, *> simply because it can't be checked at compile time. There are two ways around this:
Unsafe Cast
This is how you would deal with the problem in standard Java: just cast the LinkedHashMap<*, *> to LinkedHashMap<String, Any> (or whatever is the actual expected type). This produces a warning because the compiler can't verify the cast is safe, but it is also generally known such situations are often unavoidable when dealing with JVM generics and serialisation.
YamlConfigurationFactory(LinkedHashMap::class.java, ...) as LinkedHashMap<String, Any>
Type Inference Magic
When using Kotlin, you can avoid the cast by actually creating instance of Class<LinkedHashMap<String, Any>> explicitly. Of course, since this is still JVM, you lose all the type info at runtime, but it should be enough to tell the type inference engine what your result should be. However, you'll need a special helper method for this (or at least I haven't found a simpler solution yet), but that method needs to be declared just once somewhere in your project:
inline fun <reified T> classOf(): Class<T> = T::class.java
...
val factory = YamlConfigurationFactory(classOf<LinkedHashMap<String, Any>>(), ...)
Using this "hack", you'll get an instance of LinkedHashMap directly, however, always remember that this is just extra info for the type inference engine but effectively it just hides the unsafe cast. Also, you can't use this if the type is not known at compile type (reified).
I have a wrapped Serialization class from the serialization package in my class MySerialization. In the constroctor of MySerialization, I add a bunch of rules. Consumer classes have seperate instances of the wrapper MySerialization class to (de)serialize objects.
This setup, with a seperate instance of MySerialization in consumer classes throws an error in the Reference class constructor:
Reference(this.parent, this.ruleNumber, this.objectNumber) {
if (ruleNumber == null || objectNumber == null) {
throw new SerializationException("Invalid Reference");
}
if (parent.rules.length < ruleNumber) {
throw new SerializationException("Invalid Reference"); // <---- here
}
}
thus spawnes error in the console
Breaking on exception: SerializationException(Invalid Reference)
This means a rule cannot be found which is referenced. The starnge thing howver is, that I have the same rules applied in all Serialization instances through the MySerialization wrapper.
I tried serializing with only one instance of MySerialization. This does not spawn the error. When I debug in DartEditor, I get the <optimized out> message in the debugger window.
I have CustomRule subclasses rules defined. The behavior does not change when I enable/disabled these CustomRules
What cuases the invalid reference, and how to solve & workaround this error?
Dart Editor version 1.5.3.release (STABLE)
Dart SDK version 1.5.3
It's difficult to answer without a little more detail on your setup. However, I'm going to guess that you're using the default setup in which it will automatically generate instances of BasicRule when it encounters a class that it doesn't know about, and those are added to the list of rules. Your other instance doesn't know about those, so it fails.
You can try examining (or just printing) the list of rules in your original serialization after it has written out the objects and see if this is the case.
To fix this, you would need to write rules for the other objects that are being serialized and weren't in your original list. Or you could use the "selfDescribing" option, in which case it will send the rules that were used along with the original. But that won't work if you have hard-coded custom rules which it can't serialize.