Java Webstart and Ektorp

178 views
Skip to first unread message

Paul D. Fernhout

unread,
Apr 23, 2011, 9:03:39 PM4/23/11
to ektorp-...@googlegroups.com
Hi. My wife and I are working on some Java-based open source software for collaborating by exchanging stories using CouchDB and Ektorp.

I'm trying to get Ektorp 1.1.1 using Jackson 1.7.4 working with Java Webstart in a restricted JVM sandbox (without having to ask for all security permissions). Some security access issues are coming up in that configuration that prevent it from working. Hopefully it is some small thing that I just don't understand yet.

Just for reference, Ektorp works works fine when I do ask for permissions under webstart; thanks for the great library. From a jnlp file where it works by granting all permissions:
<security>
<all-permissions/>
</security>

I'm not entirely sure this is an Ektorp issue (compared to Jackson), although the problem with StdCouchDBConnector when checking for databases existing would seem to suggest Ektorp at least won't support Webstart without extra permissions out of the box.

Here is that error at startup with the default configuration and creating a subclass of a subclass of a class that depends on CouchDbRepositorySupport:
========================
java.security.AccessControlException: access denied (java.lang.RuntimePermission accessDeclaredMembers)
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:323)
at java.security.AccessController.checkPermission(AccessController.java:546)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
at java.lang.SecurityManager.checkMemberAccess(SecurityManager.java:1662)
at java.lang.Class.checkMemberAccess(Class.java:2157)
at java.lang.Class.getDeclaredMethods(Class.java:1790)
at org.codehaus.jackson.map.introspect.AnnotatedClass._addMemberMethods(AnnotatedClass.java:596)
at org.codehaus.jackson.map.introspect.AnnotatedClass.resolveMemberMethods(AnnotatedClass.java:532)
at org.codehaus.jackson.map.introspect.BasicClassIntrospector.forDeserialization(BasicClassIntrospector.java:151)
at org.codehaus.jackson.map.introspect.BasicClassIntrospector.forDeserialization(BasicClassIntrospector.java:16)
at org.codehaus.jackson.map.DeserializationConfig.introspect(DeserializationConfig.java:785)
at org.codehaus.jackson.map.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:303)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createDeserializer(StdDeserializerProvider.java:364)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCache2(StdDeserializerProvider.java:286)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCacheValueDeserializer(StdDeserializerProvider.java:266)
at org.codehaus.jackson.map.deser.StdDeserializerProvider.findValueDeserializer(StdDeserializerProvider.java:124)
at org.codehaus.jackson.map.deser.BasicDeserializerFactory.createCollectionDeserializer(BasicDeserializerFactory.java:242)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createDeserializer(StdDeserializerProvider.java:355)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCache2(StdDeserializerProvider.java:286)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCacheValueDeserializer(StdDeserializerProvider.java:266)
at org.codehaus.jackson.map.deser.StdDeserializerProvider.findValueDeserializer(StdDeserializerProvider.java:124)
at org.codehaus.jackson.map.deser.StdDeserializerProvider.findTypedValueDeserializer(StdDeserializerProvider.java:145)
at org.codehaus.jackson.map.ObjectMapper._findRootDeserializer(ObjectMapper.java:2195)
at org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:2129)
at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1446)
at org.ektorp.impl.StdCouchDbInstance$2.success(StdCouchDbInstance.java:64)
at org.ektorp.impl.StdCouchDbInstance$2.success(StdCouchDbInstance.java:61)
at org.ektorp.http.RestTemplate.handleResponse(RestTemplate.java:90)
at org.ektorp.http.RestTemplate.get(RestTemplate.java:22)
at org.ektorp.impl.StdCouchDbInstance.getAllDatabases(StdCouchDbInstance.java:61)
at org.ektorp.impl.StdCouchDbConnector.createDatabaseIfNotExists(StdCouchDbConnector.java:256)
at org.ektorp.support.CouchDbRepositorySupport.<init>(CouchDbRepositorySupport.java:46)
at org.rakontu.database.IndexedArchive.<init>(IndexedArchive.java:30)
at org.rakontu.database.DocumentVersionArchive.<init>(DocumentVersionArchive.java:26)
at org.rakontu.domain.StoryVersionArchive.<init>(StoryVersionArchive.java:11)
at org.rakontu.domain.Domain.<init>(Domain.java:26)
at org.rakontu.gui.RakontuApplicationWindow.initialize(RakontuApplicationWindow.java:180)
at org.rakontu.gui.RakontuApplicationWindow.<init>(RakontuApplicationWindow.java:65)
at org.rakontu.gui.RakontuApplicationWindow$1.run(RakontuApplicationWindow.java:55)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:633)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:296)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:211)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
=======================

I tried my own subclass of StdCouchDbConnector which overrides createDatabaseIfNotExists() to do nothing, as that was one place that was generating an error on startup. I figured I would deal with that later if I could get the rest of the system to work.

This is the kind of traceback related to a ChatMessage class that I'm trying to retrieve from a database. I have made sure that both ChatMessage and the superclass of it have public constructors and all public member variables and public get/set methods.

=======================
Exception in thread "AWT-EventQueue-0" org.ektorp.DbAccessException: org.codehaus.jackson.map.JsonMappingException: Can not access public org.rakontu.domain.ChatMessage() (from class org.rakontu.domain.ChatMessage; failed to set access: access denied (java.lang.reflect.ReflectPermission suppressAccessChecks)
at org.ektorp.util.Exceptions.propagate(Exceptions.java:19)
at org.ektorp.http.RestTemplate.handleResponse(RestTemplate.java:92)
at org.ektorp.http.RestTemplate.get(RestTemplate.java:22)
at org.ektorp.impl.StdCouchDbConnector.queryView(StdCouchDbConnector.java:272)
at org.rakontu.domain.ChatMessageArchive.getAllForSession(ChatMessageArchive.java:27)
at org.rakontu.gui.ChatWindow.handle_updateButton_actionPerformed(ChatWindow.java:103)
at org.rakontu.gui.ChatWindow$2.actionPerformed(ChatWindow.java:90)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2028)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2351)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
at java.awt.Component.processMouseEvent(Component.java:6352)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3267)
at java.awt.Component.processEvent(Component.java:6117)
at java.awt.Container.processEvent(Container.java:2085)
at java.awt.Component.dispatchEventImpl(Component.java:4714)
at java.awt.Container.dispatchEventImpl(Container.java:2143)
at java.awt.Component.dispatchEvent(Component.java:4544)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4621)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4282)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4212)
at java.awt.Container.dispatchEventImpl(Container.java:2129)
at java.awt.Window.dispatchEventImpl(Window.java:2478)
at java.awt.Component.dispatchEvent(Component.java:4544)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:635)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:296)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:211)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
Caused by: org.codehaus.jackson.map.JsonMappingException: Can not access public org.rakontu.domain.ChatMessage() (from class org.rakontu.domain.ChatMessage; failed to set access: access denied (java.lang.reflect.ReflectPermission suppressAccessChecks)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCache2(StdDeserializerProvider.java:291)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCacheValueDeserializer(StdDeserializerProvider.java:266)
at org.codehaus.jackson.map.deser.StdDeserializerProvider.findValueDeserializer(StdDeserializerProvider.java:124)
at org.codehaus.jackson.map.deser.StdDeserializerProvider.findTypedValueDeserializer(StdDeserializerProvider.java:145)
at org.codehaus.jackson.map.ObjectMapper._findRootDeserializer(ObjectMapper.java:2195)
at org.codehaus.jackson.map.ObjectMapper._readValue(ObjectMapper.java:2110)
at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1497)
at org.ektorp.impl.EmbeddedDocViewResponseHandler.parseFirstRow(EmbeddedDocViewResponseHandler.java:108)
at org.ektorp.impl.EmbeddedDocViewResponseHandler.success(EmbeddedDocViewResponseHandler.java:73)
at org.ektorp.impl.EmbeddedDocViewResponseHandler.success(EmbeddedDocViewResponseHandler.java:20)
at org.ektorp.http.RestTemplate.handleResponse(RestTemplate.java:90)
... 30 more
Caused by: java.lang.IllegalArgumentException: Can not access public org.rakontu.domain.ChatMessage() (from class org.rakontu.domain.ChatMessage; failed to set access: access denied (java.lang.reflect.ReflectPermission suppressAccessChecks)
at org.codehaus.jackson.map.util.ClassUtil.checkAndFixAccess(ClassUtil.java:448)
at org.codehaus.jackson.map.deser.BeanDeserializerFactory.findDeserializerCreators(BeanDeserializerFactory.java:510)
at org.codehaus.jackson.map.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:393)
at org.codehaus.jackson.map.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:370)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createDeserializer(StdDeserializerProvider.java:364)
at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCache2(StdDeserializerProvider.java:286)
... 40 more
=======================

I've tried setting
DeserializationConfig.Feature.CAN_OVERRIDE_ACCESS_MODIFIERS
to false when passing my own ObjectMapper factory in to the constructor for
that StdCouchDBConnector subclass. But it did not help much.

Note that Jackson itself can work under Java Webstart without permissions using the JsonNode or streaming approaches, but I've had similar issues with using the approach to instantiate classes directly.

Here is a simple test that generates a similar problem just using Jackson, btw.
I can get around that in theory by writing a custom deserializer (but that defeats
much of the purpose of using Jackson). So, maybe this is a broader issue with that
library? Of course, if I write such deserializers for my own classes, I might still
probably need to modify stuff in the Ektorp library to do the same?

======== Foo.java
package net.pdfernhout;

public class Foo {
public String foo;

public Foo() {

}

public String getFoo() {
return foo;
}

public void setFoo(String foo) {
this.foo = foo;
}

}

========== Test.java

package net.pdfernhout;

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;

public class Test {

private JFrame frame;
JButton testButton;

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Test window = new Test();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}

public Test() {
initialize();
}

private void initialize() {
this.frame = new JFrame();
this.frame.setBounds(100, 100, 450, 300);
this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

this.testButton = new JButton("Test");
this.testButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
handle_testButton_actionPerformed(arg0);
}
});
this.frame.getContentPane().add(this.testButton, BorderLayout.NORTH);
}

protected void handle_testButton_actionPerformed(ActionEvent arg0) {
JOptionPane.showMessageDialog(this.frame, "Test OK");
//File file = new File("/Users/pdf/Documents/workspace/TestWebstart/launch/test.html");
// Should fail under webstart without all permissions:
//JOptionPane.showMessageDialog(this.frame, "Exists: " + file.exists());
//Foo test = new Foo();
//test.setFoo("bar");

ObjectMapper m = new ObjectMapper();
try {
// This next part should work if uncommented
//JsonNode result = m.readValue("{\"foo\":\"bar\"}", JsonNode.class);
//JOptionPane.showMessageDialog(this.frame, "Jackson result (should be 'bar'): " + result.get("foo").getTextValue());
// This next part will fail under Java Webstart with no permissions
Foo test = m.readValue("{\"foo\":\"bar\"}", Foo.class);
JOptionPane.showMessageDialog(this.frame, "Jackson result with instance (should be 'bar'): " + test.getFoo());
} catch (JsonParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JsonMappingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}
}

Example of using a custom deserializer:

ObjectMapper m = new ObjectMapper();
// m.configure(DeserializationConfig.Feature.CAN_OVERRIDE_ACCESS_MODIFIERS, false);
SimpleModule module = new SimpleModule("FooModule", new Version(0, 1, 0, "alpha"));
module.addDeserializer(Foo.class, new MyCustomDeserializer());
m.registerModule(module);

===== MyCustomDeserializer.java

package net.pdfernhout;

import java.io.IOException;

import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.JsonToken;
import org.codehaus.jackson.map.DeserializationContext;
import org.codehaus.jackson.map.JsonDeserializer;

public class MyCustomDeserializer extends JsonDeserializer<Foo> {

@Override
public Foo deserialize(JsonParser jp, DeserializationContext context) throws IOException, JsonProcessingException {
// TODO Auto-generated method stub
Foo result = new Foo();
JsonToken t = jp.getCurrentToken();
System.out.println("t: " + t);
if (t == JsonToken.START_OBJECT) {
System.out.println("Start object");
t = jp.nextToken() ;
while (t != JsonToken.END_OBJECT) {
if (t != JsonToken.FIELD_NAME) throw context.mappingException(Foo.class);
String fieldName = jp.getText();
t = jp.nextToken();
String value = jp.getText();
System.out.println("Field: " + fieldName + " value: " + value);
if (fieldName.equals("foo")) result.setFoo(value);
// result.setField(fieldName, value);
t = jp.nextToken();
}
}
else {
throw context.mappingException(Foo.class);
}
return result;
}

}

===============

Any help in resolving this would be appreciated. It's possible I might just need to ask at the Jackson list?

--Paul Fernhout
http://www.pdfernhout.net/
====
The biggest challenge of the 21st century is the irony of technologies of abundance in the hands of those thinking in terms of scarcity.

henrik.lundgren

unread,
Apr 24, 2011, 7:53:30 AM4/24/11
to ektorp-discuss
The problem seem to be caused by Jackson trying to modify field or
method visibility even though it is not strictly necessary in your
example (since Foo is all public).
The reason the JsonNode class does not cause any problems is because
it is has a dedicated deserializer in Jackson which doesn't use
reflection.

I'm not sure how to get around this, I think the Jackson list may have
better input.

/H

On 24 Apr, 03:03, "Paul D. Fernhout" <pdfernh...@kurtz-fernhout.com>
wrote:
> Hi. My wife and I are working on some Java-based open source software for collaborating by exchanging stories using CouchDB and Ektorp.
>
> I'm trying to get Ektorp 1.1.1 using Jackson 1.7.4 working with Java Webstart in a restricted JVM sandbox (without having to ask for all security permissions). Some security access issues are coming up in that configuration that prevent it from working. Hopefully it is some small thing that I just don't understand yet.
>
> Just for reference, Ektorp works works fine when I do ask for permissions under webstart; thanks for the great library. From a jnlp file where it works by granting all permissions:
>   <security>
>      <all-permissions/>
>   </security>
>
> I'm not entirely sure this is an Ektorp issue (compared to Jackson), although the problem with StdCouchDBConnector when checking for databases existing would seem to suggest Ektorp at least won't support Webstart without extra permissions out of the box.
>
> Here is that error at startup with the default configuration and creating a subclass of a subclass of a class that depends on CouchDbRepositorySupport:
> ========================
> java.security.AccessControlException: access denied (java.lang.RuntimePermission accessDeclaredMembers)
>         at java.security.AccessControlContext.checkPermission(AccessControlContext.jav a:323)
>         at org.ektorp.support.CouchDbRepositorySupport.<init>(CouchDbRepositorySupport .java:46)
>         at org.rakontu.database.IndexedArchive.<init>(IndexedArchive.java:30)
>         at org.rakontu.database.DocumentVersionArchive.<init>(DocumentVersionArchive.j ava:26)
>         at org.rakontu.domain.StoryVersionArchive.<init>(StoryVersionArchive.java:11)
>         at org.rakontu.domain.Domain.<init>(Domain.java:26)
>         at org.rakontu.gui.RakontuApplicationWindow.initialize(RakontuApplicationWindo w.java:180)
>         at org.rakontu.gui.RakontuApplicationWindow.<init>(RakontuApplicationWindow.ja va:65)
>         at org.rakontu.gui.RakontuApplicationWindow$1.run(RakontuApplicationWindow.jav a:55)
>         at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
>         at java.awt.EventQueue.dispatchEvent(EventQueue.java:633)
>         at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.jav a:296)
>         at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:2 11)
>         at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.jav a:201)
>         at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196)
>         at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188)
>         at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
> =======================
>
> I tried my own subclass of StdCouchDbConnector which overrides createDatabaseIfNotExists() to do nothing, as that was one place that was generating an error on startup. I figured I would deal with that later if I could get the rest of the system to work.
>
> This is the kind of traceback related to a ChatMessage class that I'm trying to retrieve from a database. I have made sure that both ChatMessage and the superclass of it have public constructors and all public member variables and public get/set methods.
>
> =======================
> Exception in thread "AWT-EventQueue-0" org.ektorp.DbAccessException: org.codehaus.jackson.map.JsonMappingException: Can not access public org.rakontu.domain.ChatMessage() (from class org.rakontu.domain.ChatMessage; failed to set access: access denied (java.lang.reflect.ReflectPermission suppressAccessChecks)
>         at org.ektorp.util.Exceptions.propagate(Exceptions.java:19)
>         at org.ektorp.http.RestTemplate.handleResponse(RestTemplate.java:92)
>         at org.ektorp.http.RestTemplate.get(RestTemplate.java:22)
>         at org.ektorp.impl.StdCouchDbConnector.queryView(StdCouchDbConnector.java:272)
>         at org.rakontu.domain.ChatMessageArchive.getAllForSession(ChatMessageArchive.j ava:27)
>         at org.rakontu.gui.ChatWindow.handle_updateButton_actionPerformed(ChatWindow.j ava:103)
>         at org.rakontu.gui.ChatWindow$2.actionPerformed(ChatWindow.java:90)
>         at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2028)
>         at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2351 )
>         at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java: 387)
>         at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
>         at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListene r.java:236)
>         at java.awt.Component.processMouseEvent(Component.java:6352)
>         at javax.swing.JComponent.processMouseEvent(JComponent.java:3267)
>         at java.awt.Component.processEvent(Component.java:6117)
>         at java.awt.Container.processEvent(Container.java:2085)
>         at java.awt.Component.dispatchEventImpl(Component.java:4714)
>         at java.awt.Container.dispatchEventImpl(Container.java:2143)
>         at java.awt.Component.dispatchEvent(Component.java:4544)
>         at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4621)
>         at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4282)
>         at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4212)
>         at java.awt.Container.dispatchEventImpl(Container.java:2129)
>         at java.awt.Window.dispatchEventImpl(Window.java:2478)
>         at java.awt.Component.dispatchEvent(Component.java:4544)
>         at java.awt.EventQueue.dispatchEvent(EventQueue.java:635)
>         at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.jav a:296)
>         at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:2 11)
>         at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.jav a:201)
>         at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196)
>         at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188)
>         at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
> Caused by: org.codehaus.jackson.map.JsonMappingException: Can not access public org.rakontu.domain.ChatMessage() (from class org.rakontu.domain.ChatMessage; failed to set access: access denied (java.lang.reflect.ReflectPermission suppressAccessChecks)
>         at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCache2(Std DeserializerProvider.java:291)
>         at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCacheValue Deserializer(StdDeserializerProvider.java:266)
>         at org.codehaus.jackson.map.deser.StdDeserializerProvider.findValueDeserialize r(StdDeserializerProvider.java:124)
>         at org.codehaus.jackson.map.deser.StdDeserializerProvider.findTypedValueDeseri alizer(StdDeserializerProvider.java:145)
>         at org.codehaus.jackson.map.ObjectMapper._findRootDeserializer(ObjectMapper.ja va:2195)
>         at org.codehaus.jackson.map.ObjectMapper._readValue(ObjectMapper.java:2110)
>         at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1497)
>         at org.ektorp.impl.EmbeddedDocViewResponseHandler.parseFirstRow(EmbeddedDocVie wResponseHandler.java:108)
>         at org.ektorp.impl.EmbeddedDocViewResponseHandler.success(EmbeddedDocViewRespo nseHandler.java:73)
>         at org.ektorp.impl.EmbeddedDocViewResponseHandler.success(EmbeddedDocViewRespo nseHandler.java:20)
>         at org.ektorp.http.RestTemplate.handleResponse(RestTemplate.java:90)
>         ... 30 more
> Caused by: java.lang.IllegalArgumentException: Can not access public org.rakontu.domain.ChatMessage() (from class org.rakontu.domain.ChatMessage; failed to set access: access denied (java.lang.reflect.ReflectPermission suppressAccessChecks)
>         at org.codehaus.jackson.map.util.ClassUtil.checkAndFixAccess(ClassUtil.java:44 8)
>         at org.codehaus.jackson.map.deser.BeanDeserializerFactory.findDeserializerCrea tors(BeanDeserializerFactory.java:510)
>         at org.codehaus.jackson.map.deser.BeanDeserializerFactory.buildBeanDeserialize r(BeanDeserializerFactory.java:393)
>         at org.codehaus.jackson.map.deser.BeanDeserializerFactory.createBeanDeserializ er(BeanDeserializerFactory.java:370)
>         at org.codehaus.jackson.map.deser.StdDeserializerProvider._createDeserializer( StdDeserializerProvider.java:364)
>         at org.codehaus.jackson.map.deser.StdDeserializerProvider._createAndCache2(Std DeserializerProvider.java:286)
> --Paul Fernhouthttp://www.pdfernhout.net/

Paul D. Fernhout

unread,
Apr 24, 2011, 12:43:31 PM4/24/11
to ektorp-...@googlegroups.com
On 4/24/11 7:53 AM, henrik.lundgren wrote:
> The problem seem to be caused by Jackson trying to modify field or
> method visibility even though it is not strictly necessary in your
> example (since Foo is all public).
> The reason the JsonNode class does not cause any problems is because
> it is has a dedicated deserializer in Jackson which doesn't use
> reflection.
>
> I'm not sure how to get around this, I think the Jackson list may have
> better input.

Henrik-

Thanks for the reply.

Yes, I think that is what is going on, and I agree makes no obvious sense to me, as everything is public. I thought for a bit maybe it was because I did not declare a public constructor, but even when I do declare one, and with or without calling super() in the constructor, the problem still occurs.

I can wonder if it is a bug either in the JVM I am using or in Jackson? But that seems unlikely, so there is probably something going on I don't understand. I just put in a question on the Jackson user list to at least understand why it is going on.
http://archive.codehaus.org/lists/org.codehaus.jackson.user/

As a workaround, I'm thinking about just using JsonNode as my document type in Ektorp and wrapping classes around that. Because it is a new application, I don't especially need POJOs as I could just have each instance keep its state in a JsonNode it holds onto and have getter/setters work with that wrapped JsonNode tree.

Although Ektorp provides other options, being such a well-designed library, :-) like I could parse a returned query stream directly as well using any deserializer I wanted. And then there are custom deserializers. There might even be more options I don't know of. So, I think I could make it work eventually one way or another.

Related code for overriding StdCouchDbConnector to prevent Extorp from having a webstart issue when trying to create databases:

class MyConnector extends StdCouchDbConnector {

public MyConnector(String databaseName, CouchDbInstance dbInstance, ObjectMapperFactory om) {
super(databaseName, dbInstance, om);
}

public void createDatabaseIfNotExists() {
// Overriden to do nothing -- trying to get around webstart issue
}
}

...
db = new MyConnector("your-database", dbInstance, mySingletonObjectMapperFactory);

Ultimately though, while this seems to be a Jackson issue, I would need to change or override anything in Ektorp itself that caused an issue as well to get webstart without permissions, like the code to create databases. For an end-user application that does not call the replication code and so on, the more advanced features of Ektorp like that might not be needed, so there may be not much that I would need to override or change just to have CRUD and querying and maybe changes working well enough to go with webstart if I use a JsonNode approach.

Anyway, thanks again for the reply. Right now I'm just including a request for all permissions, so things work fine with webstart. But it is unfortunate to request that, since there is no permission or signing that should be really required since the application just stores data using a CouchDB server. I'll post an update if I learn anything relevant for Ektorp from the Jackson list about this issue.

--Paul Fernhout

Paul D. Fernhout

unread,
Apr 26, 2011, 2:06:38 PM4/26/11
to ektorp-...@googlegroups.com
On 4/24/11 12:43 PM, Paul D. Fernhout wrote:
> Ultimately though, while this seems to be a Jackson issue, I would
> need to change or override anything in Ektorp itself that caused an
> issue as well to get webstart without permissions, like the code to
> create databases. For an end-user application that does not call the
> replication code and so on, the more advanced features of Ektorp like
> that might not be needed, so there may be not much that I would need
> to override or change just to have CRUD and querying and maybe
> changes working well enough to go with webstart if I use a JsonNode
> approach.

No news from the Jackson list so far:
http://markmail.org/message/q2vi5ombueiubkhu

But here are some Ektorp related code snippets as I try to make this work anyway, using classes that wrap JsonNodes.

I am getting some other execptions.

Here is one, but I got around it, so it is just here for reference as it relates to the Ektorp code:

Exception in thread "AWT-EventQueue-0" org.ektorp.DbAccessException: java.lang.reflect.InvocationTargetException
at org.ektorp.util.Exceptions.propagate(Exceptions.java:19)
at org.ektorp.util.Documents$MethodAccessor.setRevision(Documents.java:238)
at org.ektorp.util.Documents.setRevision(Documents.java:79)
at org.ektorp.impl.StdCouchDbConnector.create(StdCouchDbConnector.java:80)
at org.rakontu.database.Domain.add(Domain.java:37)
at org.rakontu.gui.ChatWindow.handle_sendButton_actionPerformed(ChatWindow.java:178)

Here is code from the Ektorp Documents class:

===
private Method findAnnotatedMethod(Class<?> clazz,
String annotationValue, Class<?> returnType) {
for (Method me : clazz.getDeclaredMethods()) {
JsonProperty a = me.getAnnotation(JsonProperty.class);
if (a != null && a.value().equals(annotationValue)
&& returnType.isAssignableFrom(me.getReturnType())) {
me.setAccessible(true);
return me;
}
}

===

I define an _rev annotation, but it is in a superclass.

Note how it does a setAccessible, even when it might need to, and the exception is not caught. Documents does that in three places.
But I don't think that is what is causing the issue, as it happens even under regular Java. But it might be a webstart issue eventually.
It is not easy how to get past that without modifying the library code, as I need to override StdCouchDbConnector create(), but it uses private fields for restTemplate, revisionHandler, and dbURI.

I can wonder if this is more the issue?
http://download.oracle.com/javase/1.5.0/docs/api/java/lang/Class.html#getDeclaredMethods%28%29
http://java.sun.com/javase/6/docs/api/java/lang/Class.html#getDeclaredMethods() "Returns an array of Method objects reflecting all the methods declared by the class or interface represented by this Class object. This includes public, protected, default (package) access, and private methods, but excludes inherited methods."

Is Ektorp checking recursively for methods for annotations, or is it just looking in the one class?

There seems to be a Sun JVM bug report connected to whether that method should return inherited methods sometimes or not:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6815786

See AnnotatedClass.java in Jackson for code that goes up the chain like this:

======
public void resolveMemberMethods(MethodFilter methodFilter, boolean collectIgnored)
{
_memberMethods = new AnnotatedMethodMap();
AnnotatedMethodMap mixins = new AnnotatedMethodMap();
// first: methods from the class itself
_addMemberMethods(_class, methodFilter, _memberMethods, _primaryMixIn, mixins);

// and then augment these with annotations from super-types:
for (Class<?> cls : _superTypes) {
Class<?> mixin = (_mixInResolver == null) ? null : _mixInResolver.findMixInClassFor(cls);
_addMemberMethods(cls, methodFilter, _memberMethods, mixin, mixins);
}
....

=======

Also this snippet may be of interest is this setup stuff I did with Ektorp, even though it was not good enough with the revision issue -- but this may not be needed as I just discovered the create(idString, JsonNode) method in CouchDbConnector which lets me get around that issue in another way:

====

StdCouchDbConnector db = new MyConnector("rakontu-using-ektorp", dbInstance, JSONObjectMapperSingleton.SINGLETON);
db.setJsonSerializer(new StreamingJsonSerializer(JSONObjectMapperSingleton.SINGLETON.objectMapper) {
@Override
public String toJson(Object o) {
if (o instanceof AbstractResource) {
AbstractResource abstractResource = (AbstractResource) o;
return super.toJson(abstractResource.getRootNode());
} else {
return super.toJson(o);
}
}

});

====

I also had an issue with ComplexKeys where Ektorp tried to add a String as a Pojo and Jackson through an error, which I solved by doing this (this may not handle nulls properly if nulls are written out in the data, as it maps nulls to "{}"):

// To get around issues with webstart and ektorp trying to make POJO nodes with ComplexKey
public String complexKey(String k1) {
if (k1 == null) k1 = "{}";
else k1 = "\"" + k1 + "\"";

return "[" + k1 + "]";
}

public String complexKey(String k1, String k2) {
if (k1 == null) k1 = "{}";
else k1 = "\"" + k1 + "\"";

if (k2 == null) k2 = "{}";
else k2 = "\"" + k2 + "\"";

return "[" + k1 + "," + k2 + "]";
}

public String complexKey(String k1, String k2, String k3) {
if (k1 == null) k1 = "{}";
else k1 = "\"" + k1 + "\"";

if (k2 == null) k2 = "{}";
else k2 = "\"" + k2 + "\"";

if (k3 == null) k3 = "{}";
else k3 = "\"" + k3 + "\"";

return "[" + k1 + "," + k2 + "," + k3 + "]";
}

====

I am discovering that on writing out JsonNode (but not reading with) the ObjectMapper generates a security exception,
at least for 1.8.0.

I've was finding workarounds to the other things without changing library code.
But now I am a bit stumped by Jackson generating exceptions on just serializing JsonNodes to a string.
That was unexpected.

I would need to use a separate JSON serializer from someone else to now serialize Jackson JsonNodes? :-)
Maybe there is some option I am missing, but otherwise I might need to
start modifying that Jackson library to adjust something about how it writes out JsonNodes?
I think a main Jackson person who answers stuff on the list has gone on vacation for a couple weeks though,
so my other question may be a while in getting answered.

Anyway, I am thinking this should not be so hard to use JSON with webstart, because that is a natural fit
for JSON when talking to a server, so I must be missing something.

I was trying to figure out how to create a SecurityManager that mimics what webstart does
so this is all easier to test as a test case, but not luck so far on that.

Henrik Lundgren

unread,
Apr 27, 2011, 3:02:29 AM4/27/11
to ektorp-...@googlegroups.com
Hi, see my answers below:

On Tue, Apr 26, 2011 at 8:06 PM, Paul D. Fernhout
<pdfer...@kurtz-fernhout.com> wrote:
> On 4/24/11 12:43 PM, Paul D. Fernhout wrote:
>> Ultimately though, while this seems to be a Jackson issue, I would
>> need to change or override anything in Ektorp itself that caused an
>> issue as well to get webstart without permissions, like the code to
>> create databases. For an end-user application that does not call the
>> replication code and so on, the more advanced features of Ektorp like
>> that might not be needed, so there may be not much that I would need
>> to override or change just to have CRUD and querying and maybe
>> changes working well enough to go with webstart if I use a JsonNode
>> approach.
>
> No news from the Jackson list so far:
>  http://markmail.org/message/q2vi5ombueiubkhu
>
> But here are some Ektorp related code snippets as I try to make this work anyway, using classes that wrap JsonNodes.
>
> I am getting some other execptions.
>
> Here is one, but I got around it, so it is just here for reference as it relates to the Ektorp code:
>
> Exception in thread "AWT-EventQueue-0" org.ektorp.DbAccessException: java.lang.reflect.InvocationTargetException
>        at org.ektorp.util.Exceptions.propagate(Exceptions.java:19)
>        at org.ektorp.util.Documents$MethodAccessor.setRevision(Documents.java:238)
>        at org.ektorp.util.Documents.setRevision(Documents.java:79)
>        at org.ektorp.impl.StdCouchDbConnector.create(StdCouchDbConnector.java:80)
>        at org.rakontu.database.Domain.add(Domain.java:37)
>        at org.rakontu.gui.ChatWindow.handle_sendButton_actionPerformed(ChatWindow.java:178)
>

This error is caused by that something failed in the setRevision
method in your document class. The method should be the one annotated
with @JsonProperty("_rev")

> Here is code from the Ektorp Documents class:
>
> ===
>                private Method findAnnotatedMethod(Class<?> clazz,
>                        String annotationValue, Class<?> returnType) {
>                        for (Method me : clazz.getDeclaredMethods()) {
>                                JsonProperty a = me.getAnnotation(JsonProperty.class);
>                                if (a != null && a.value().equals(annotationValue)
>                                                && returnType.isAssignableFrom(me.getReturnType())) {
>                                        me.setAccessible(true);
>                                        return me;
>                                }
>                        }
>
> ===
>
> I define an _rev annotation, but it is in a superclass.
>
> Note how it does a setAccessible, even when it might need to, and the exception is not caught. Documents does that in three places.
> But I don't think that is what is causing the issue, as it happens even under regular Java. But it might be a webstart issue eventually.
> It is not easy how to get past that without modifying the library code, as I need to override StdCouchDbConnector create(), but it uses private fields for restTemplate, revisionHandler, and dbURI.
>

You can register your own document accessor: see
http://www.ektorp.org/reference_documentation.html#d99e470
You can also register a custom Jackson serializer for your class with
the @JsonSerialize annotation, this might alow you to get around the
security manager.

> I can wonder if this is more the issue?
>  http://download.oracle.com/javase/1.5.0/docs/api/java/lang/Class.html#getDeclaredMethods%28%29
>  http://java.sun.com/javase/6/docs/api/java/lang/Class.html#getDeclaredMethods() "Returns an array of Method objects reflecting all the methods declared by the class or interface represented by this Class object. This includes public, protected, default (package) access, and private methods, but excludes inherited methods."
>
> Is Ektorp checking recursively for methods for annotations, or is it just looking in the one class?

It is checking recursively

I don't recommend this approach. You should be able to do anything you
want with Java classes or JsonNodes

> I also had an issue with ComplexKeys where Ektorp tried to add a String as a Pojo and Jackson through an error, which I solved by doing this (this may not handle nulls properly if nulls are written out in the data, as it maps nulls to "{}"):
>
>        // To get around issues with webstart and ektorp trying to make POJO nodes with ComplexKey
>        public String complexKey(String k1) {
>                if (k1 == null) k1 = "{}";
>                else k1 = "\"" + k1 + "\"";
>
>                return "[" + k1 + "]";
>        }
>
>        public String complexKey(String k1, String k2) {
>                if (k1 == null) k1 = "{}";
>                else k1 = "\"" + k1 + "\"";
>
>                if (k2 == null) k2 = "{}";
>                else k2 = "\"" + k2 + "\"";
>
>                return "[" + k1 + "," + k2 + "]";
>        }
>
>        public String complexKey(String k1, String k2, String k3) {
>                if (k1 == null) k1 = "{}";
>                else k1 = "\"" + k1 + "\"";
>
>                if (k2 == null) k2 = "{}";
>                else k2 = "\"" + k2 + "\"";
>
>                if (k3 == null) k3 = "{}";
>                else k3 = "\"" + k3 + "\"";
>
>                return "[" + k1 + "," + k2 + "," + k3 + "]";
>        }
>
> ====
>

Complex keys are best handled by the org.ektorp.CompleKey class

> I am discovering that on writing out JsonNode (but not reading with) the ObjectMapper generates a security exception,
> at least for 1.8.0.
>
> I've was finding workarounds to the other things without changing library code.
> But now I am a bit stumped by Jackson generating exceptions on just serializing JsonNodes to a string.
> That was unexpected.
>
> I would need to use a separate JSON serializer from someone else to now serialize Jackson JsonNodes? :-)
> Maybe there is some option I am missing, but otherwise I might need to
> start modifying that Jackson library to adjust something about how it writes out JsonNodes?
> I think a main Jackson person who answers stuff on the list has gone on vacation for a couple weeks though,
> so my other question may be a while in getting answered.
>
> Anyway, I am thinking this should not be so hard to use JSON with webstart, because that is a natural fit
> for JSON when talking to a server, so I must be missing something.
>
> I was trying to figure out how to create a SecurityManager that mimics what webstart does
> so this is all easier to test as a test case, but not luck so far on that.

Is there a way to disable the security manager since is causing you so
much trouble?

Paul D. Fernhout

unread,
Apr 29, 2011, 12:42:33 PM4/29/11
to ektorp-...@googlegroups.com
On 4/27/11 3:02 AM, Henrik Lundgren wrote:
> Is there a way to disable the security manager since is causing you so
> much trouble?

Thanks for the great suggestions.

Yes, I'm seeing that maybe Java under webstart is a great idea in
theory, but in practice has lots of issues.

I'm finding the same sorts of issues trying to use JGraphX under
webstart, where it does its own serialization and runs into similar
security issues.

IHMO, the security model of Java should just be just at the VM level
(what services could be accessed like opening specific ports or writing
to specific files or using other specific OS services). The Java
security manager overhead to check every access related to
public/private/default/protected seems to be the cause of many
unfortunate access issues as well as probably performance overhead.

So, maybe it is not worth trying to fix running under webstart in that
sense, because the more I look, the more it seems many people who use
webstart give up trying to ship unsigned applications and either sign
them or pick another technology like JavaScript for those aspects.
Webstart with unsigned applications has other issues too (like having a
warning label on all your windows) that may discourage its use.

Reply all
Reply to author
Forward
0 new messages