{"action":"opened","issue":{"url":"https://api.github.com/repos/asciidoctor/asciidoctorj/issues/450","repository_url":"https://api.github.com/repos/asciidoctor/asciidoctorj","labels_url":"https://api.github.com/repos/asciidoctor/asciidoctorj/issues/450/labels{/name}","comments_url":"https://api.github.com/repos/asciidoctor/asciidoctorj/issues/450/comments","events_url":"https://api.github.com/repos/asciidoctor/asciidoctorj/issues/450/events","html_url":"https://github.com/asciidoctor/asciidoctorj/issues/450","id":148886403,"number":450,"title":"Block processor attributes is Map<String, Object> but may contain non-String keys.","user":{"login":"jjaderberg","id":6028968,"avatar_url":"https://avatars.githubusercontent.com/u/6028968?v=3","gravatar_id":"","url":"https://api.github.com/users/jjaderberg","html_url":"https://github.com/jjaderberg","followers_url":"https://api.github.com/users/jjaderberg/followers","following_url":"https://api.github.com/users/jjaderberg/following{/other_user}","gists_url":"https://api.github.com/users/jjaderberg/gists{/gist_id}","starred_url":"https://api.github.com/users/jjaderberg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jjaderberg/subscriptions","organizations_url":"https://api.github.com/users/jjaderberg/orgs","repos_url":"https://api.github.com/users/jjaderberg/repos","events_url":"https://api.github.com/users/jjaderberg/events{/privacy}","received_events_url":"https://api.github.com/users/jjaderberg/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":0,"created_at":"2016-04-16T20:09:01Z","updated_at":"2016-04-16T20:09:01Z","closed_at":null,"body":"A block processor needs to take a `Map<String, Object>` argument for \"attributes\", but the map that is passed may contain non-String keys.\r\n\r\nThe following block processor throws a `java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.String` when treating all map keys as strings.\r\nThe exception is thrown in the for loop because one or more keys in the map are `Integer`s.\r\nIf I change the *style* of the block in the AsciiDoc source to `source`, no exception is thrown.\r\n\r\nMy guess is that \"custom attributes\" are keyed by `Integer`s in the attributes map.\r\nIf that's the case, maybe the signature of `BlockProcessor#process()` should type 'attributes' as `Map<Object, Object>`, or maybe some type coersion magic needs to happen to make sure the generics of the map in the signature are respected.\r\n\r\nIt works to treat the map as if it were `<Object, Object>`, at least for the `Integer` case.\r\nSince there is a `Integer#toString()` method, treating a key as an `Object` in the for loop works just fine.\r\n\r\nBlock processor:\r\n\r\n    import org.asciidoctor.ast.StructuralNode;\r\n    import org.asciidoctor.extension.BlockProcessor;\r\n    import org.asciidoctor.extension.Reader;\r\n\r\n    import java.util.HashMap;\r\n    import java.util.Map;\r\n\r\n    public class UnexpectedIntegerKeysBlockProcessor extends BlockProcessor {\r\n\r\n        private static Map<String, Object> configs = new HashMap<String, Object>() {{\r\n            put(CONTEXTS, CONTEXT_LISTING);\r\n        }};\r\n\r\n        public UnexpectedIntegerKeysBlockProcessor(String name, Map<String,Object> config) {\r\n            super(name, configs);\r\n        }\r\n\r\n        @Override\r\n        public Object process(StructuralNode parent, Reader reader, Map<String,Object> attributes) {\r\n            for (String key : attributes.keySet()) {\r\n                System.out.println(key + \": \" + attributes.get(key));\r\n            }\r\n            return null;\r\n        }\r\n    }\r\n\r\n\r\nTest:\r\n\r\n    import org.asciidoctor.Asciidoctor;\r\n    import org.asciidoctor.OptionsBuilder;\r\n    import org.junit.Test;\r\n\r\n    import java.io.File;\r\n    import java.net.URISyntaxException;\r\n\r\n    import static org.asciidoctor.Asciidoctor.Factory.create;\r\n\r\n    public class UnexpectedIntegerKeysBlockProcessorTest {\r\n\r\n        @Test\r\n        public void attributesShouldOnlyContainStringKeys() {\r\n\r\n            Asciidoctor asciidoctor = create();\r\n            asciidoctor.javaExtensionRegistry().block(\"snippet\", UnexpectedIntegerKeysBlockProcessor.class);\r\n\r\n            try {\r\n                File referenceFile =\r\n                        new File(getClass().getClassLoader().getResource(\"unexpectedintegerkeys.adoc\").toURI ());\r\n                String referenceResult = asciidoctor.convertFile(referenceFile, OptionsBuilder.options()\r\n                        .headerFooter( false )\r\n                        .toFile( false ));\r\n            } catch (URISyntaxException ex) {\r\n                System.out.println( ex.getMessage() );\r\n            }\r\n        }\r\n    }\r\n\r\n\r\nAsciiDoc source:\r\n\r\n    [snippet, java]\r\n    ----\r\n    Java code.\r\n    ----\r\n"}}