Using a when clause in an enum class getter in Kotlin - enums

I'm trying to get a specific getter of a property in kotlin to be based on the value of the enum it is called from. This is what I got so far:
enum class Endpoint {
EVENTS, GAMES;
val baseUrl = "https://www.example.com/api"
val path: String
get() = when(this){
EVENTS -> "$baseUrl/events"
GAMES -> "$baseUrl/games"
}
}
Called like this:
print(Endpoint.EVENTS.path)
While this compiles without any problem, as soon as I run it I get a NullPointerException with the error Attempt to invoke virtual method 'java.lang.Object [...].Endpoint[].clone()' on a null object reference
I'm not sure what I'm doing wrong or what the proper way to accomplish what is stated above is.
EDIT: Full log of the exception:
05-09 22:51:33.793 15673-15673/com.filippovigani.eventvods E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.filippovigani.eventvods, PID: 15673
java.lang.ExceptionInInitializerError
at com.filippovigani.eventvods.networking.Endpoint.getPath(Endpoint.kt:21)
at com.filippovigani.eventvods.networking.Endpoint.<init>(Endpoint.kt:25)
at com.filippovigani.eventvods.networking.Endpoint.<clinit>(Endpoint.kt)
at com.filippovigani.eventvods.networking.EventvodsApi$Companion.getEvents(EventvodsApi.kt:8)
at com.filippovigani.eventvods.MainActivity.onCreate(MainActivity.kt:19)
at android.app.Activity.performCreate(Activity.java:5990)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387)
at android.app.ActivityThread.access$800(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object com.filippovigani.eventvods.networking.Endpoint[].clone()' on a null object reference
at com.filippovigani.eventvods.networking.Endpoint.values(Endpoint.kt)
at com.filippovigani.eventvods.networking.Endpoint$WhenMappings.<clinit>(Unknown Source)
at com.filippovigani.eventvods.networking.Endpoint.getPath(Endpoint.kt:21) 
at com.filippovigani.eventvods.networking.Endpoint.<init>(Endpoint.kt:25) 
at com.filippovigani.eventvods.networking.Endpoint.<clinit>(Endpoint.kt) 
at com.filippovigani.eventvods.networking.EventvodsApi$Companion.getEvents(EventvodsApi.kt:8) 
at com.filippovigani.eventvods.MainActivity.onCreate(MainActivity.kt:19) 
at android.app.Activity.performCreate(Activity.java:5990) 
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106) 
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2278) 
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2387) 
at android.app.ActivityThread.access$800(ActivityThread.java:151) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:135) 
at android.app.ActivityThread.main(ActivityThread.java:5254) 
at java.lang.reflect.Method.invoke(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:372) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698) 

I can't reproduce your error, the code works fine. Nevertheless, I think the solution is a bit too complex, why don't you use a constructor argument to provide the constant-specific value:
enum class Endpoint(service: String) {
EVENTS("/events"), GAMES("/games");
private val baseUrl = "https://www.example.com/api"
val path: String = baseUrl + service
}

The exception indicates you're trying to access path within the constructor of the enum. This causes a problem because the enum is not yet ready for use during construction.
This means the following chain of calls results in failure:
Init Endpoint
Init Endpoint.EVENTS
Call to Endpoint.getPath() (This does not show in your code)
Uses Endpoint$WhenMapping, begin init of that class.
Endpoint$WhenMapping uses EndPoint.values(), but since we're still initializing the instances of the enum, the values array cannot be provided, returning null.
To ensure it is not modified, WhenMapping clones and caches the array, but since the array is null when it never should be outside of initialization this causes the NPE.
Simply put your code somehow relies on a class that requires itself to be fully initialized to use. Since your code does not display how you're calling Endpoint.EVENTS.path this is all that can be said about it.

Related

Firestore's WriteBatch.update() won't take angularfirestore2's AngularFirestoreDocument

I'm trying to do a batch write using Firestore's WriteBatch. I'm trying to add updates to the WriteBatch and that requires a DocumentReference. I have a AngularFirestoreDocument and can't figure out how to cast that to a DocumentReference and get it to compile or run correctly.
I've tried to cast it to any,unknown, and DocumentReference and use the AngularFirestoreDocument as is.
export class FinancialService {
private transCollection: AngularFirestoreCollection<Transaction>;
batch_update_trans(trans) {
let writer = this.afs.firestore.batch();
this.transCollection = this.afs.collection<Transaction>('balance_sheets/'+this.balance_sheet_id+"/transactions/");
for (let t of trans) {
writer.update(this.transCollection.doc(id),t);
}
return writer.commit();
}
}
if I include the AngularFirestoreDocument as is like above I get this compile time error:
error TS2345: Argument of type 'AngularFirestoreDocument<{}>' is not assignable to parameter of type 'DocumentReference'.
Type 'AngularFirestoreDocument<{}>' is missing the following properties from type 'DocumentReference': id, firestore, parent, path, and 2 more.
If I cast the AngularFirestoreDocument to a DocumentReference:
writer.update(<DocumentReference>this.transCollection.doc(id),t);
I get this compile time error:
error TS2352: Conversion of type 'AngularFirestoreDocument<{}>' to type 'DocumentReference' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
Type 'AngularFirestoreDocument<{}>' is missing the following properties from type 'DocumentReference': id, firestore, parent, path, and 2 more
If I cast the AngularFirestoreDocument to a DocumentReference to unknown:
writer.update(<unknown> this.transCollection.doc(id),t);
It fails to compile with this error:
error TS2345: Argument of type 'unknown' is not assignable to parameter of type 'DocumentReference'.
If I cast the AngularFirestoreDocument to a DocumentReference to any:
writer.update(<any> this.transCollection.doc(id),t);
it does compile, but I get a runtime error when I try go batch update docs this way:
Uncaught (in promise): FirebaseError: [code=invalid-argument]: Function WriteBatch.update() requires its first argument to be a DocumentReference, but it was: an object
FirebaseError: Function WriteBatch.update() requires its first argument to be a DocumentReference, but it was: an object
I was expecting the code to compile and successfully batch update Transaction docs.
OK, I figured out how to do this using this really helpful article that provides a lot of documentation that angularfire2 doesn't have itself:
Firestore Advanced Usage : angularfire - atomic writes
You can access the javascript API through angularfire2's firestore module and create a DocumentRef through that API, instead of using angularfire2's AngularFirestoreDocument type.
The working code looks like this:
export class FinancialService {
batch_update_trans(trans) {
let writer = this.afs.firestore.batch();
let transDoc = null;
for (let t of trans) {
transDoc = this.afs.firestore.doc(
'balance_sheets/'+this.balance_sheet_id+"/transactions/"+t.id);
writer.update(transDoc,t);
}
return writer.commit();
}
}

How to use build in pipelinefunctions in a member function?

Aim is to use the buil in groovy-function in a member function of a class.
Running the following code with default jenkins in ubuntu18.04 leads to the following error.
It looks like jenkins is searching for a function called 'dir' in defined in the class itself.
If important I'll check pipeline version an jenkins vaersion later.
copy&past pipelinescript:
class notworkingClass {
notworkingClass(){}
public MyFunction(){
dir('/my/local/folder'){
dosomething() // never reached
}
}
}
def x = new notworkingClass()
x.MyFunction()
This is the stack trace:
hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: notworkingClass.dir() is applicable for argument types: (java.lang.String, org.jenkinsci.plugins.workflow.cps.CpsClosure2) values: [/my/local/folder, org.jenkinsci.plugins.workflow.cps.CpsClosure2#372fc690]
Possible solutions: wait(), dump(), find(), any(), is(java.lang.Object), every()
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:58)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:64)
at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:54)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.kohsuke.groovy.sandbox.impl.Checker$1.call(Checker.java:157)
at org.kohsuke.groovy.sandbox.GroovyInterceptor.onMethodCall(GroovyInterceptor.java:23)
at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onMethodCall(SandboxInterceptor.java:155)
at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onMethodCall(SandboxInterceptor.java:142)
at org.kohsuke.groovy.sandbox.impl.Checker$1.call(Checker.java:155)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedCall(Checker.java:159)
at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.methodCall(SandboxInvoker.java:17)
at notworkingClass.MyFunction(WorkflowScript:5)
at WorkflowScript.run(WorkflowScript:12)
at ___cps.transform___(Native Method)
#Cutton Eye I found some message from here, I think the explanation is : Library classes cannot directly call steps such as sh or git, but we can call it through a Scripted Pipeline
Found the solution... just wan't do say, it's not obvious and I've no idea why this is working at all. If somebody could explaint this to me, I would be more then happy! from here
The magic line is this Script script thing in the sample class.
class A {
Script script;
public void a() {
script.echo("Hello")
script.sh('pwd')
}
}
node('master'){
def a = new A(script:this)
echo "Calling A.a()"
a.a()
}
It's like take this context as class and reference it to the variable or something...
But i still look for a way in not cheating with the constructor, a member function like this:
public testFunction(MyArg){
hudson.jenkins.hidding.function.entry.echo(MyArg)
// from my understanding, there must be something like this
}
By hitting
println(WorkflowScript.metaClass.methods*.name.sort().unique())
it shows that it at least not part of the WorkflowScript:
[$build, $buildNoException, blubb, equals, evaluate, #
getBinding, getClass, getMetaClass, getProperty, hashCode,
invokeMethod, main, notify, notifyAll, print, printf, println,
run, setBinding, setMetaClass, setProperty, sleep, toString, wait]

Build a Custom Tokenizer for elasticsearch

I'm building a custom tokenizer in response to this: Performance of doc_values field vs analysed field
None of this API appears to be documented (?), so I'm going off of code samples from other plugins/tokenizers, but when I restart elastic having deployed my tokenizer I get this error constantly in the logs:
[2017-09-20 08:45:37,412][WARN ][indices.cluster ] [Samuel Silke] [[storm-crawler-2017-09-11][3]] marking and sending shard failed due to [failed to create index]
[storm-crawler-2017-09-11] IndexCreationException[failed to create index]; nested: CreationException[Guice creation errors:
1) Could not find a suitable constructor in com.cameraforensics.elasticsearch.plugins.UrlTokenizerFactory. Classes must have either one (and only one) constructor annotated with #Inject or a zero-argument constructor that is not private.
at com.cameraforensics.elasticsearch.plugins.UrlTokenizerFactory.class(Unknown Source)
at org.elasticsearch.index.analysis.TokenizerFactoryFactory.create(Unknown Source)
at org.elasticsearch.common.inject.assistedinject.FactoryProvider2.initialize(Unknown Source)
at _unknown_
1 error];
at org.elasticsearch.indices.IndicesService.createIndex(IndicesService.java:360)
at org.elasticsearch.indices.cluster.IndicesClusterStateService.applyNewIndices(IndicesClusterStateService.java:294)
at org.elasticsearch.indices.cluster.IndicesClusterStateService.clusterChanged(IndicesClusterStateService.java:163)
at org.elasticsearch.cluster.service.InternalClusterService.runTasksForExecutor(InternalClusterService.java:610)
at org.elasticsearch.cluster.service.InternalClusterService$UpdateTask.run(InternalClusterService.java:772)
at org.elasticsearch.common.util.concurrent.PrioritizedEsThreadPoolExecutor$TieBreakingPrioritizedRunnable.runAndClean(PrioritizedEsThreadPoolExecutor.java:231)
at org.elasticsearch.common.util.concurrent.PrioritizedEsThreadPoolExecutor$TieBreakingPrioritizedRunnable.run(PrioritizedEsThreadPoolExecutor.java:194)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.elasticsearch.common.inject.CreationException: Guice creation errors:
1) Could not find a suitable constructor in com.cameraforensics.elasticsearch.plugins.UrlTokenizerFactory. Classes must have either one (and only one) constructor annotated with #Inject or a zero-argument constructor that is not private.
at com.cameraforensics.elasticsearch.plugins.UrlTokenizerFactory.class(Unknown Source)
at org.elasticsearch.index.analysis.TokenizerFactoryFactory.create(Unknown Source)
at org.elasticsearch.common.inject.assistedinject.FactoryProvider2.initialize(Unknown Source)
at _unknown_
1 error
at org.elasticsearch.common.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.java:360)
at org.elasticsearch.common.inject.InjectorBuilder.injectDynamically(InjectorBuilder.java:172)
at org.elasticsearch.common.inject.InjectorBuilder.build(InjectorBuilder.java:110)
at org.elasticsearch.common.inject.InjectorImpl.createChildInjector(InjectorImpl.java:157)
at org.elasticsearch.common.inject.ModulesBuilder.createChildInjector(ModulesBuilder.java:55)
at org.elasticsearch.indices.IndicesService.createIndex(IndicesService.java:358)
... 9 more
My tokenizer is built for v2.3.4, and the TokenizerFactory looks like this:
public class UrlTokenizerFactory extends AbstractTokenizerFactory {
#Inject
public UrlTokenizerFactory(Index index, IndexSettingsService indexSettings, #Assisted String name, #Assisted Settings settings){
super(index, indexSettings.getSettings(), name, settings);
}
#Override
public Tokenizer create() {
return new UrlTokenizer();
}
}
I genuinely don't know what I'm doing wrong. Have I deployed it incorrectly? It appears to be using my classes according to the logs...
I've only deployed it to one of my es nodes (4-node cluster). The /_cat/plugins?v endpoint gives this:
name component version type url
Samuel Silke urltokenizer 2.3.4.0 j
As there's little or no documentation on this process, I've got this far by copying constructs as created in plugins by other people.
The error I'm seeing doesn't make sense. My TokenizerFactory looks just like everyone else's for this version of elastic. What am I doing wrong or, possibly, not doing that I should be to make this work?
Turns out I was missing an Environment variable. It should have been this:
public UrlTokenizerFactory(Index index, IndexSettingsService indexSettings, Environment env, #Assisted String name, #Assisted Settings settings){
...
I found a similar one here in the end: https://github.com/codelibs/elasticsearch-analysis-kuromoji-neologd/blob/2.3.x/src/main/java/org/codelibs/elasticsearch/kuromoji/neologd/index/analysis/KuromojiTokenizerFactory.java

Lagom framework / streamed response / websocket / pathCall / Descriptor / Creator instead of Function

I have my service declared this way:
public interface BlogQueryService extends Service {
public ServiceCall<String, Source<String, ?>> tick(int interval);
public ServiceCall<String, Source<String, ?>> tock();
public ServiceCall<NotUsed, Source<PostSummary, ?>> newPosts();
public ServiceCall<String, Source<PostSummary, ?>> getPostSummaries();
#Override
default Descriptor descriptor() {
return named("blog-query").with(
//pathCall("/api/bloggie/tick/:interval", this::tick),
pathCall("/api/bloggie/tock", tock())
//pathCall("/api/bloggie/newPosts", this::newPosts),
//pathCall("/api/bloggie/postSummaries", this::getPostSummaries)
).withAutoAcl(true);
}
}
The tick works. The tock doesn't.
When I invoke it using websocket client (to ws://localhost:9000/api/bloggie/tock ) , I got "undefined" as response, indicating no mapping found for that URL.
After some experimentings, found out why: tick works because it has url param (the :interval). Tick doesn't work because it doesn't have url param. Seriously pathCall requires you to have param in your URL? So I checked the API of Service: http://www.lagomframework.com/documentation/1.0.x/api/java/com/lightbend/lagom/javadsl/api/Service.html
There are several overloaded declarations of pathCall. Apparently the tick uses this one:
static <Request,Response,A> Descriptor.Call<Request,Response> pathCall(String pathPattern, akka.japi.function.Function<A,ServiceCall<Request,Response>> methodRef)
So from the signature, yes it requires the method to take a parameter. So, if the method (such is tock) doesn't take a param, the binding will fail at runtime. So I guess I need to use this one instead:
static <Request,Response> Descriptor.Call<Request,Response> pathCall(String pathPattern, akka.japi.function.Creator<ServiceCall<Request,Response>> methodRef)
The problem is... I don't know how. I haven't seen any example of the use of akka.japi.function.Creator in pathCall.
I tried this:
default Descriptor descriptor() {
return named("blog-query").with(
pathCall("/api/bloggie/tick/:interval", this::tick),
pathCall("/api/bloggie/tock", new Creator<ServiceCall<String, Source<String, ?>>> () {
public ServiceCall<String, Source<String, ?>> create() {
return tock();
}
})
//pathCall("/api/bloggie/newPosts", this::newPosts),
//pathCall("/api/bloggie/postSummaries", this::getPostSummaries)
).withAutoAcl(true);
}
It compiles. But it throws an error at runtime:
com.google.inject.CreationException: Unable to create injector, see the following errors:
1) Error in custom provider, java.lang.IllegalStateException: Unable to resolve method for service call with ID PathCallId{pathPattern='/api/bloggie/tock'}. Ensure that the you have passed a method reference (ie, this::someMethod). Passing anything else, for example lambdas, anonymous classes or actual implementation classes, is forbidden in declaring a service descriptor.
at com.lightbend.lagom.javadsl.server.ServiceGuiceSupport.bindServices(ServiceGuiceSupport.java:43) (via modules: com.google.inject.util.Modules$OverrideModule -> sample.bloggie.impl.BlogServiceModule)
while locating com.lightbend.lagom.internal.server.ResolvedServices
Thanks in advance!
I just did some experiments... All compiled, but none of them works....
namedCall("/api/bloggie/tock", this::tock)
Result: Compile success. Runtime: path unknown (no binding (?)).
Then I tried
pathCall("/api/bloggie/tock", () -> this.tock())
Result: exception.
com.google.inject.CreationException: Unable to create injector, see the following errors:
1) Error in custom provider, scala.MatchError: Request (of class sun.reflect.generics.reflectiveObjects.TypeVariableImpl)
at com.lightbend.lagom.javadsl.server.ServiceGuiceSupport.bindServices(ServiceGuiceSupport.java:43) (via modules: com.google.inject.util.Modules$OverrideModule -> sample.bloggie.impl.BlogServiceModule)
while locating com.lightbend.lagom.internal.server.ResolvedServices
for parameter 1 at com.lightbend.lagom.internal.server.ServiceRegistrationModule$RegisterWithServiceRegistry.<init>(ServiceRegistrationModule.scala:55)
at com.lightbend.lagom.internal.server.ServiceRegistrationModule.bindings(ServiceRegistrationModule.scala:29):
Binding(class com.lightbend.lagom.internal.server.ServiceRegistrationModule$RegisterWithServiceRegistry to self eagerly) (via modules: com.google.inject.util.Modules$OverrideModule -> play.api.inject.guice.GuiceableModuleConversions$$anon$1)
while locating com.lightbend.lagom.internal.server.ServiceRegistrationModule$RegisterWithServiceRegistry
Then I tried:
public ServiceCall<NotUsed, Source<String, ?>> tock(Void x);
Result: exception
com.google.inject.CreationException: Unable to create injector, see the following errors:
1) Error in custom provider, java.lang.IllegalArgumentException: Don't know how to serialize ID class java.lang.Void
at com.lightbend.lagom.javadsl.server.ServiceGuiceSupport.bindServices(ServiceGuiceSupport.java:43) (via modules: com.google.inject.util.Modules$OverrideModule -> sample.bloggie.impl.BlogServiceModule)
Update: "Solved" (partially). Figured out that this one works:
pathCall("/tock", this::tock)
I can open it using this URL: ws://localhost:9000/tock
So..., I can't have nicely structured URL for those functions that returns stream, when those functions need no param? At least for now (?).
UPDATE: seems like this problem is happening not only with pathCall. I encountered the same problem with rest call. This one doesn't work (no binding):
public ServiceCall<NotUsed, PSequence<PostSummary>> getPostSummaries();
...
restCall(Method.GET, "/api/bloggie/postSummaries", this::getPostSummaries)
This one works:
public ServiceCall<NotUsed, PSequence<PostSummary>> getPostSummaries();
...
restCall(Method.GET, "/postSummaries", this::getPostSummaries)
Thanks!
So firstly, namedCall should only be used if you don't care about the path. You are invoking the service call directly, which means you do care about the path, so you have to use pathCall or restCall.
This should work:
pathCall("/api/bloggie/tock", this::tock)
Also, I think you're not pasting the full errors. Make sure you check right to the bottom of the list of Guice errors, that should explain exactly what the problem is, in many of the cases above, the problem is that you're not passing a method reference, you're passing a lambda, and the error message should say that.

Camel type converter fails: InvalidPayloadException: No body available of type

The application is based on OSGI.
I have a custom annotated converter:
package com.domain.bundle1.web.camel.converters;
import ...;
#Converter
public class FooTransferObjectConverter {
public FooTransferObjectConverter() {
}
#Converter
public static FooTransferObject toFooTransferObject(Foo foo, Exchange exchange) throws Exception {
// some magic
return fooTransferObject;
}
}
Also i declared package where it plased in TypeConverter file:
http://i.stack.imgur.com/U3QQH.png
which contains:
com.domain.bundle1.web.camel.converters
And camel-context file contains next code:
<log loggingLevel="INFO" message="Converting to FooTransferObject" />
<convertBodyTo type="com.domain.bundle2.model.FooTransferObject" />
<log loggingLevel="INFO" message="Converted!" />
Before converting, body of message is a Foo object.
But when process reaches converting, then throws an exception:
Failed delivery for (MessageId: ID-EPUALVIW0567-55536-1401106375216-26-5 on ExchangeId: ID-EPUALVIW0567-55536-1401106375216-26-6).
Exhausted after delivery attempt: 1 caught: org.apache.camel.InvalidPayloadException: No body available of type: com.domain.bundle2.model.FooTransferObject but has value: Foo{97, Wall, null, null} of type: com.domain.bundle3.model.Foo on: Message: Foo{97, Wall, null, null}.
Caused by: Error during type conversion from type: com.domain.bundle3.model.Foo to the required type: com.domain.bundle2.model.FooTransferObject with value Foo{97, Wall, null, null} due 6 counts of IllegalAnnotationExceptions. Exchange[Message: Foo{97, Wall, null, null}]. Caused by: [org.apache.camel.TypeConversionException - Error during type conversion from type: Foo{97, Wall, null, null} to the required type: com.domain.bundle2.model.FooTransferObjec with value....
then exception cached by custom handler,
and then I found this:
Caused by: javax.xml.bind.MarshalException
- with linked exception:
[com.sun.istack.internal.SAXException2: A cycle is detected in the object graph. This will cause infinitely deep XML: freebaseball SpeedKick -> fr????f????tb??ll Sp????dK??ck -> free
football SpeedKick ]
at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:311)[:1.7.0_40]
at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:236)[:1.7.0_40]
at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:95)
at org.apache.camel.converter.jaxb.FallbackTypeConverter.marshall(FallbackTypeConverter.java:238)
at org.apache.camel.converter.jaxb.FallbackTypeConverter.convertTo(FallbackTypeConverter.java:95)
... 163 more
Caused by: com.sun.istack.internal.SAXException2: A cycle is detected in the object graph. This will cause infinitely deep XML: freebaseball SpeedKick -> fr????f????tb??ll Sp????dK??c
k -> freebaseball SpeedKick
at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.reportError(XMLSerializer.java:237)[:1.7.0_40]
How do You think what's a problem? How can I see loaded converters in TypeConverterRegistry?
I have already solved my problem. FallbackTypeConverter started work, because camel didn't load my custom regular type converter.
I checked the map of converters in TypeConverterRegister in debug mode, and didn't find my FooTransferObjectConverter.
The problem was in file TypeConverter. I just added name of converter class to path and after that it loaded to registry.
com.domain.bundle1.web.camel.converters.FooTransferObjectConverter
Camel version in application - 2.11.1. In camel docs written next:
In Camel 2.8 we improved the type converter loader to support
specifying the FQN class name of the converter classes. This has the
advantage of avoiding having to scan packages for #Converter classes.
Instead it loads the #Converter class directly. This is a highly
recommend approach to use going forward.
But i tryed run the application from chapter 3 (from 'Camel in action' book) with custom converter. And file TypeConverter contained only from package path.

Resources