{"action":"closed","issue":{"url":"https://api.github.com/repos/uniVocity/univocity-parsers/issues/27","labels_url":"https://api.github.com/repos/uniVocity/univocity-parsers/issues/27/labels{/name}","comments_url":"https://api.github.com/repos/uniVocity/univocity-parsers/issues/27/comments","events_url":"https://api.github.com/repos/uniVocity/univocity-parsers/issues/27/events","html_url":"https://github.com/uniVocity/univocity-parsers/issues/27","id":75099530,"number":27,"title":"Add CsvFieldOrder annotation","user":{"login":"mlvn23","id":5626477,"avatar_url":"https://avatars.githubusercontent.com/u/5626477?v=3","gravatar_id":"","url":"https://api.github.com/users/mlvn23","html_url":"https://github.com/mlvn23","followers_url":"https://api.github.com/users/mlvn23/followers","following_url":"https://api.github.com/users/mlvn23/following{/other_user}","gists_url":"https://api.github.com/users/mlvn23/gists{/gist_id}","starred_url":"https://api.github.com/users/mlvn23/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mlvn23/subscriptions","organizations_url":"https://api.github.com/users/mlvn23/orgs","repos_url":"https://api.github.com/users/mlvn23/repos","events_url":"https://api.github.com/users/mlvn23/events{/privacy}","received_events_url":"https://api.github.com/users/mlvn23/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/uniVocity/univocity-parsers/labels/enhancement","name":"enhancement","color":"84b6eb"}],"state":"closed","locked":false,"assignee":{"login":"jbax","id":7100478,"avatar_url":"https://avatars.githubusercontent.com/u/7100478?v=3","gravatar_id":"","url":"https://api.github.com/users/jbax","html_url":"https://github.com/jbax","followers_url":"https://api.github.com/users/jbax/followers","following_url":"https://api.github.com/users/jbax/following{/other_user}","gists_url":"https://api.github.com/users/jbax/gists{/gist_id}","starred_url":"https://api.github.com/users/jbax/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jbax/subscriptions","organizations_url":"https://api.github.com/users/jbax/orgs","repos_url":"https://api.github.com/users/jbax/repos","events_url":"https://api.github.com/users/jbax/events{/privacy}","received_events_url":"https://api.github.com/users/jbax/received_events","type":"User","site_admin":false},"milestone":{"url":"https://api.github.com/repos/uniVocity/univocity-parsers/milestones/1","html_url":"https://github.com/uniVocity/univocity-parsers/milestones/1.6.0","labels_url":"https://api.github.com/repos/uniVocity/univocity-parsers/milestones/1/labels","id":1076485,"number":1,"title":"1.6.0","description":null,"creator":{"login":"jbax","id":7100478,"avatar_url":"https://avatars.githubusercontent.com/u/7100478?v=3","gravatar_id":"","url":"https://api.github.com/users/jbax","html_url":"https://github.com/jbax","followers_url":"https://api.github.com/users/jbax/followers","following_url":"https://api.github.com/users/jbax/following{/other_user}","gists_url":"https://api.github.com/users/jbax/gists{/gist_id}","starred_url":"https://api.github.com/users/jbax/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jbax/subscriptions","organizations_url":"https://api.github.com/users/jbax/orgs","repos_url":"https://api.github.com/users/jbax/repos","events_url":"https://api.github.com/users/jbax/events{/privacy}","received_events_url":"https://api.github.com/users/jbax/received_events","type":"User","site_admin":false},"open_issues":6,"closed_issues":4,"state":"open","created_at":"2015-04-21T04:44:44Z","updated_at":"2015-05-11T13:11:42Z","due_on":null,"closed_at":null},"comments":2,"created_at":"2015-05-11T05:56:42Z","updated_at":"2015-05-11T13:11:42Z","closed_at":"2015-05-11T13:11:42Z","body":"The one thing I really liked about this library is the Bean annotation feature! With it, I was able to write a generic toCsv and fromCsv routines similar to how you could use Jackson without passing metadata (unlike SuperCsv). The only quirk I found was declaring the headers to determine which fields to write and in what order. I believe this can be enhanced by introducing a CsvFieldOrder annotation (which I did) at the class level of the Bean. \r\n\r\nI did it like this (it's in Scala, but I think you get the idea):\r\n\r\n```\r\n@Retention(RetentionPolicy.RUNTIME)\r\n@Target(ElementType.TYPE)\r\npublic @interface CsvFieldOrder {\r\n    String[] fields();\r\n}\r\n\r\n    def toCsv[T: Manifest](records: Seq[T], filename: String, headers: Option[Seq[String]] = None)\r\n        (implicit tag: ClassTag[T]): Unit = {\r\n\r\n        val cls = tag.runtimeClass.asInstanceOf[Class[T]]\r\n        val processor = new BeanWriterProcessor[T](cls)\r\n\r\n        val settings = new CsvWriterSettings\r\n        settings.setRowWriterProcessor(processor)\r\n        headers.map { h =>\r\n            settings.setHeaders(h: _*)\r\n        } getOrElse {\r\n            val order = cls.getAnnotation(classOf[CsvFieldOrder])\r\n            if (order == null) {\r\n                throw new IllegalArgumentException(\r\n                    \"CsvFieldOrder annotation not found and headers is none\"\r\n                )\r\n            } else {\r\n                settings.setHeaders(order.fields():_*)\r\n            }\r\n        }\r\n\r\n        val outputStream = new FileOutputStream(filename)\r\n        val outputWriter = new OutputStreamWriter(outputStream)\r\n        val w = new CsvWriter(outputWriter, settings)\r\n        w.writeHeaders()\r\n        w.processRecordsAndClose(records.asJava)\r\n\r\n    }\r\n```"}}