I seem to be having a problem with case insensitivity. I have a class with two methods whose names differ only in case that causes the scanner to have problems.
More specifically, I have a response class for my REST API:
public interface Job {
#CheckForNull
List<Job> getPredecessors();
#CheckForNull
String getPREDECESSORS();
}
This class is autogenerated in the build, and it really is the intention to have two different getters that are similarly named, but with different capitalizations.
When swagger scans my classes I get an error:
Caused by: java.lang.IllegalArgumentException: Conflicting getter definitions for property "predecessors": com.termalabs.ac.rest.Job#getPREDECESSORS(0 params) vs com.termalabs.ac.rest.Job#getPredecessors(0 params)
at com.fasterxml.jackson.databind.introspect.POJOPropertyBuilder.getGetter(POJOPropertyBuilder.java:244)
at com.fasterxml.jackson.databind.introspect.POJOPropertyBuilder.getAccessor(POJOPropertyBuilder.java:364)
at com.fasterxml.jackson.databind.introspect.POJOPropertyBuilder.getPrimaryMember(POJOPropertyBuilder.java:396)
at io.swagger.jackson.ModelResolver.resolve(ModelResolver.java:306)
at io.swagger.jackson.ModelResolver.resolve(ModelResolver.java:183)
at io.swagger.converter.ModelConverterContextImpl.resolve(ModelConverterContextImpl.java:100)
at io.swagger.jackson.ModelResolver.resolve(ModelResolver.java:234)
at io.swagger.jackson.ModelResolver.resolve(ModelResolver.java:183)
at io.swagger.converter.ModelConverterContextImpl.resolve(ModelConverterContextImpl.java:100)
at io.swagger.jackson.ModelResolver.resolveProperty(ModelResolver.java:159)
at io.swagger.jackson.ModelResolver.resolveProperty(ModelResolver.java:110)
at io.swagger.converter.ModelConverterContextImpl.resolveProperty(ModelConverterContextImpl.java:80)
at io.swagger.converter.ModelConverters.readAsProperty(ModelConverters.java:58)
at io.swagger.jaxrs.Reader.parseMethod(Reader.java:896)
at io.swagger.jaxrs.Reader.read(Reader.java:322)
at io.swagger.jaxrs.Reader.read(Reader.java:172)
at io.swagger.jaxrs.config.BeanConfig.scanAndRead(BeanConfig.java:242)
at io.swagger.jaxrs.config.BeanConfig.setScan(BeanConfig.java:221)
at com.termalabs.server.restapi.JawsSwaggerApplication.<init>(JawsSwaggerApplication.java:40)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.jboss.resteasy.core.ConstructorInjectorImpl.construct(ConstructorInjectorImpl.java:150)
... 18 more
Apparently jackson can't handle having two different getters with the same spelling but different capitalizations. This is strange to me because both java and Json are case sensitive.
I can find some references to MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES in jackson, but I can't figure out how to use it.
Is there a way to make this scanning of my services case sensitive?
Thanks,
Michael
Related
I'm trying to run a very basic script with org.jetbrains.kotlin:kotlin-scripting-jvm, but I get two errors, when I should get none. This is my script:
1
I expect to get back a ResultWithDiagnostics.Success with a resultValue of 1 but instead I get a Failure, with these reports:
The expression is unused
wrong number of arguments
Even if I fix the warning by modifying my script to
class Foo(val foo: String = "foo")
Foo()
I still get the wrong number of arguments error. I checked the source and it seems that in
BasicJvmScriptEvaluator:95
return try {
ctor.newInstance(*args.toArray()) <-- here
} finally {
Thread.currentThread().contextClassLoader = saveClassLoader
}
args is empty. What am I doing wrong? This is how I try to run the script:
private fun evalFile(scriptFile: File): ResultWithDiagnostics<EvaluationResult> {
val compilationConfiguration = createJvmCompilationConfigurationFromTemplate<TestScript> {
jvm {
dependenciesFromCurrentContext(wholeClasspath = true)
}
}
return BasicJvmScriptingHost().eval(scriptFile.toScriptSource(), compilationConfiguration, null)
}
and this is the stack trace for this wrong number of arguments error I get:
java.lang.IllegalArgumentException: wrong number of arguments
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at kotlin.script.experimental.jvm.BasicJvmScriptEvaluator.evalWithConfigAndOtherScriptsResults(BasicJvmScriptEvaluator.kt:95)
at kotlin.script.experimental.jvm.BasicJvmScriptEvaluator.invoke$suspendImpl(BasicJvmScriptEvaluator.kt:40)
at kotlin.script.experimental.jvm.BasicJvmScriptEvaluator.invoke(BasicJvmScriptEvaluator.kt)
at kotlin.script.experimental.host.BasicScriptingHost$eval$1.invokeSuspend(BasicScriptingHost.kt:47)
at kotlin.script.experimental.host.BasicScriptingHost$eval$1.invoke(BasicScriptingHost.kt)
at kotlin.script.experimental.host.BasicScriptingHost$runInCoroutineContext$1.invokeSuspend(BasicScriptingHost.kt:35)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:238)
at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.kt:116)
at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:80)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:54)
at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:36)
at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
at kotlin.script.experimental.host.BasicScriptingHost.runInCoroutineContext(BasicScriptingHost.kt:35)
at kotlin.script.experimental.host.BasicScriptingHost.eval(BasicScriptingHost.kt:45)
This isn't fix, just workaround.
You can pass the source code to Kotlin Compiler by the different ways:
From FileScriptSource - when you pass list of files in the configuration
From the list of source code content in memory - e.g. each file should be read and content should be placed inside StringScriptSource
From the single memory script, which is created just with all input source files concatenation.
As I found in my experiments:
If you have mockk+kotest jars in the same classpath, option 1 doesn't work. In that case I'd like to assume for you to make one change:
// this doesn't work - scriptFile.toScriptSource()
scriptFile.readText().toScriptSource() // ok - we read source from memory, not from file
If you have huge service with a lot of Spring jars, all options above work. It means that you couldn't test your compilation in the unit tests, however your service will work!
If you want to do compilation from Gradle Plugin, you can catch another kind of issue - class conflict with coroutines library, so all options above don't work.
Finally, I changed the following in my code:
On input I always have a lot of kt/kts files.
I have three compilation options (described above). So my code executes createJvmCompilationConfigurationFromTemplate with the different logic, according on my compilation mode (it is just enum).
For unit tests I have to use option 3 only.
For service I use the first option as it is the fastest one
For gradle plugin classpath I start separate instance of java (with fresh classpath) which executes the input kts files.
I have some xtend code that gets a parse tree/AST from a file in my DSL.
I want a method that will serialize any node in the tree. This means I want text in the language of my DSL for an EObject somewhere in the parse tree.
So, if a program in my language is
class C {
int foo = 3;
}
the parse tree might look like
MyProgram
|_ MyClass
|_MyFieldDecl
|_Type
| |_IntType
|_Identifier
|_Expression
|_LiteralInteger
If I assigned a variable x the MyFieldDecl object in the tree, then I might want to call
var s = serialize(x)
to get the String, "int foo = 3;"
So, how do I implement that serialize() function?
The code I find when searching around will serialize the entire tree but not a node/fragment.
I found things in the xtext core code that appear to be doing this with either some instance of ISerializer or GrammarAccessExtensions. I tried to inject
#Inject #Extension GrammarAccessExtensions _grammarAccessExtensions
and get the serialization using
val s = _grammarAccessExtensions.grammarFragmentToString(e, prefix);
where e is an EObject, some node in the parse tree.
That failed on the statement
val main = injector.getInstance(MyClass)
with this error:
Exception in thread "main" com.google.inject.ConfigurationException: Guice configuration errors:
1) No implementation for org.eclipse.xtext.xtext.generator.model.project.IXtextProjectConfig was bound.
while locating org.eclipse.xtext.xtext.generator.model.project.IXtextProjectConfig
for field at org.eclipse.xtext.xtext.generator.XtextGeneratorNaming.projectConfig(Unknown Source)
while locating org.eclipse.xtext.xtext.generator.XtextGeneratorNaming
for field at org.eclipse.xtext.xtext.generator.grammarAccess.GrammarAccessExtensions._xtextGeneratorNaming(Unknown Source)
while locating org.eclipse.xtext.xtext.generator.grammarAccess.GrammarAccessExtensions
for field at myorg.MyClass._grammarAccessExtensions(Unknown Source)
while locating myorg.MyClass
1 error
at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1004)
at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:961)
at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1013)
at myorg.MyClass.main(MyClass.java:435)
I think this means I need to bind or inject things, but I just started working with this code base a couple of days ago, and all of this is new to me.
I also tried to copy code out of the xtext core to get an ISerializer and call
s = GrammarAccessExtensions.grammarFragmentToString(serializer, e, prefix)
That failed with this:
java.lang.NullPointerException: Invalid context: Grammar returns ScenarioModel
According to Phillip Riand (see: discussion on openNTF) this is not possible... They need to know the design element to find out who signed it. Therefore, it is only available in SSJS.
There are 2 ways that I know of to use the sessionAsSigner object in Java beans:
1 By resolving the sessionAsSigner object:
FacesContext context = FacesContext.getCurrentInstance();
Session sessionAsSigner = context.getApplication().getVariableResolver().
resolveVariable(context, "sessionAsSigner");
2 By using the getCurrentSessionAsSigner() function from the com.ibm.xsp.extlib.util.ExtLibUtil class in the Extension Library.
To be able to use it (in Java as wel as SSJS) you'll want to make sure that all design elements were signed by the same user ID. If that's not the case, the sessionAsSigner object will not be available ('undefined').
I found that the solution is right at hand :-)
I changed my XPage (in this example an XAgent) to:
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" rendered="false">
This is an xAgent returning json data...
<xp:this.afterRenderResponse><![CDATA[#{javascript:Controller.verify(sessionAsSigner)}]]></xp:this.afterRenderResponse>
and in the bean I simply used the session in the argument when I needed to open a database/document as signer. Sometimes the solution is so simple :-)
/John
This is quite an old post that I just stumbled upon. Tried some of the solutions mentioned above:
resolveVariable did not work for me, at least not for sessionAsSigner as this throws a runtime error (I can resolve plain old session, though...)
to be honest I didn't quite understand the Controller.verify(sessionAsSigner) method; is Controller something specific to XAgents? If so, I don't have an XAgent here, so can't use it
didn't feel like importing extra ExtLib classes here...
So I came up with another solution that appears to be very simple:
created a method in my javaBean that takes a session object as argument; since sessionAsSigner belongs to the same class as session I don't have to import something new.
Javacode is:
public void testSession(Session s) throws Exception{
System.out.println(" > test effective user for this session = "
+ s.getEffectiveUserName());
}
This is called from SSJS as either
mybean.testSession(session);
or
myBean.testSession(sessionAsSigner);
Maybe helps others, too
I want to retrieve a Map from a using JAX-RS (text/xml)
#GET
public Map<String,String> getMap(){
}
but I am getting the error below:
0000001e FlushResultHa E org.apache.wink.server.internal.handlers.FlushResultHandler handleResponse The system could not find a javax.ws.rs.ext.MessageBodyWriter or a DataSourceProvider class for the java.util.HashMap type and application/x-ms-application mediaType. Ensure that a javax.ws.rs.ext.MessageBodyWriter exists in the JAX-RS application for the type and media type specified.
[10:43:52:885 IST 07/02/12] 0000001e RequestProces I org.apache.wink.server.internal.RequestProcessor logException The following error occurred during the invocation of the handlers chain: WebApplicationException (500 - Internal Server Error) with message 'null' while processing GET request sent to http://localhost:9080/jaxrs_module/echo/upload/getSiteNames
The solution I choose is to wrap a Map and use it for the return param.
#XmlRootElement
public class JaxrsMapWrapper {
private Map<String,String> map;
public JaxrsMapWrapper(){
}
public void setMap(Map<String,String> map) {
this.map = map;
}
public Map<String,String> getMap() {
return map;
}
}
and the method signature will go like this
#GET
public JaxrsMapWrapper getMap()
Your problem is that the default serialization strategy (use JAXB) means that you can't serialize that map directly. There are two main ways to deal with this.
Write an XmlAdaptor
There are a number of questions on this on SO but the nicest explanation I've seen so far is on the CXF users mailing list from a few years ago. The one tricky bit (since you don't want an extra wrapper element) is that once you've got yourself a type adaptor, you've got to install it using a package-level annotation (on the right package, which might take some effort to figure out). Those are relatively exotic.
Write a custom MessageBodyWriter
It might well be easier to write your own code to do the serialization. To do this, you implement javax.ws.rs.ext.MessageBodyWriter and tag it with #Provider (assuming that you are using an engine that uses that to manage registration; not all do for complex reasons that don't matter too much here). This will let you produce exactly the document you want from any arbitrary type at a cost of more complexity when writing (but at least you won't be having complex JAXB problems). There are many ways to actually generate XML, with which ones to choose between depending on the data to be serialized
Note that if you were streaming the data out rather than assembling everything in memory, you'd have to implement this interface.
Using CXF 2.4.2, it supports returning Map from the api. I use jackson-jaxrs 1.9.6 for serialization.
#Path("participation")
#Consumes({"application/json"})
#Produces({"application/json"})
public interface SurveyParticipationApi {
#GET
#Path("appParameters")
Map<String,String> getAppParameters();
....
}
With CXF 2.7.x use
WebClient.postCollection(Object collection, Class<T> memberClass, Class<T> responseClass)
,like this in your rest client code.
(Map<String, Region>) client.postCollection(regionCodes, String.class,Map.class);
for other collections use WebClient.postAndGetCollection().
I have an object with embedded members that I'm making persistent without problems using RDBMS and MySQL.
When I change the datastore to S3 (json plugin) I get the following exception:
Dec 30, 2011 9:50:30 AM org.datanucleus.state.JDOStateManagerImpl isLoaded
WARNING: Exception thrown by StateManager.isLoaded
This constructor is only for objects using application identity.
org.datanucleus.exceptions.NucleusUserException: This constructor is only for objects using application identity.
at org.datanucleus.state.JDOStateManagerImpl.initialiseForHollowAppId(JDOStateManagerImpl.java:226)
at org.datanucleus.state.ObjectProviderFactory.newForHollowPopulatedAppId(ObjectProviderFactory.java:119)
at org.datanucleus.store.json.fieldmanager.FetchFieldManager.getObjectFromJSONObject(FetchFieldManager.java:322)
at org.datanucleus.store.json.fieldmanager.FetchFieldManager.fetchObjectField(FetchFieldManager.java:250)
at org.datanucleus.state.AbstractStateManager.replacingObjectField(AbstractStateManager.java:2228)
at myproject.MyObject.jdoReplaceField(Unknown Source)
at myproject.MyObject.jdoReplaceFields(Unknown Source)
at org.datanucleus.state.JDOStateManagerImpl.replaceFields(JDOStateManagerImpl.java:1949)
at org.datanucleus.state.JDOStateManagerImpl.replaceFields(JDOStateManagerImpl.java:1976)
at org.datanucleus.store.json.JsonPersistenceHandler.fetchObject(JsonPersistenceHandler.java:269)
at org.datanucleus.state.JDOStateManagerImpl.loadFieldsFromDatastore(JDOStateManagerImpl.java:1652)
at org.datanucleus.state.JDOStateManagerImpl.loadSpecifiedFields(JDOStateManagerImpl.java:1254)
at org.datanucleus.state.JDOStateManagerImpl.isLoaded(JDOStateManagerImpl.java:1742)
at myproject.MyObject.jdoGetmember_(Unknown Source)
at myproject.MyObject.getMember(Unknown Source)
member_ in myproject.MyObject is defined as:
#Persistent
#Embedded(members = {
...
})
private Member member_;
and
#PersistenceCapable(detachable="true")
#EmbeddedOnly
public class Member implements Serializable {
(no application identity, no key)
The jdoconfig.xml is roughly:
<jdoconfig
xmlns="http://java.sun.com/xml/ns/jdo/jdoconfig"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://java.sun.com/xml/ns/jdo/jdoconfig">
<persistence-manager-factory name="trans-optional">
<property name="javax.jdo.PersistenceManagerFactoryClass"
value="org.datanucleus.api.jdo.JDOPersistenceManagerFactory"/>
<property name="datanucleus.ConnectionURL"
value="amazons3:http://s3.amazonaws.com/"/>
<property name="datanucleus.ConnectionUserName"
value="..."/>
<property name="datanucleus.ConnectionPassword"
value="..."/>
<property name="datanucleus.cloud.storage.bucket"
value="mybucket"/>
</persistence-manager-factory>
</jdoconfig>
I've been to the Supported Features table but I must admit I don't fully understand it.
Does it say that the json plugin does NOT supports embedded objects?
Why do my embedded objects need to have application identity? If I define them with application identity I'm also asked to provide a key and I don't want that, I want them to be embedded.
Any help will be much appreciated!
As the Supported Features table says very clearly (to me), there is a CROSS against the JSON datastore column for the feature "Embedded PC", hence it is not supported for that datastore. Obviously if some user/company wanted such a feature they could either
Update the JSON plugin to support it, like was done for the ODF
plugin for example
Sponsor that work.
Alternatively, don't use embedded objects with that datastore.