Use stax for file generation
Project: http://git-wip-us.apache.org/repos/asf/karaf-boot/repo Commit: http://git-wip-us.apache.org/repos/asf/karaf-boot/commit/af6327ca Tree: http://git-wip-us.apache.org/repos/asf/karaf-boot/tree/af6327ca Diff: http://git-wip-us.apache.org/repos/asf/karaf-boot/diff/af6327ca Branch: refs/heads/master Commit: af6327ca53b12afc27e573aab9dce0ddc76d9a27 Parents: 5e0846f Author: Christian Schneider <[email protected]> Authored: Mon Apr 25 18:30:19 2016 +0200 Committer: Christian Schneider <[email protected]> Committed: Mon Apr 25 18:30:19 2016 +0200 ---------------------------------------------------------------------- samples/jpa/pom.xml | 33 ++-- starters/karaf-boot-starter-jpa/pom.xml | 61 +++--- .../karaf/boot/jpa/impl/JpaProcessor.java | 198 +++++++++++-------- .../karaf/boot/jpa/impl/JpaProcessorTest.java | 64 ++++++ .../src/test/resources/expected_persistence.xml | 11 ++ 5 files changed, 241 insertions(+), 126 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/karaf-boot/blob/af6327ca/samples/jpa/pom.xml ---------------------------------------------------------------------- diff --git a/samples/jpa/pom.xml b/samples/jpa/pom.xml index 032396f..1c51404 100644 --- a/samples/jpa/pom.xml +++ b/samples/jpa/pom.xml @@ -1,23 +1,17 @@ <?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - - <!-- - - Licensed to the Apache Software Foundation (ASF) under one or more - contributor license agreements. See the NOTICE file distributed with - this work for additional information regarding copyright ownership. - The ASF licenses this file to You under the Apache License, Version 2.0 - (the "License"); you may not use this file except in compliance with - the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - --> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <!-- Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with this + work for additional information regarding copyright ownership. The ASF licenses + this file to You under the Apache License, Version 2.0 (the "License"); you + may not use this file except in compliance with the License. You may obtain + a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless + required by applicable law or agreed to in writing, software distributed + under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + OR CONDITIONS OF ANY KIND, either express or implied. See the License for + the specific language governing permissions and limitations under the License. --> <modelVersion>4.0.0</modelVersion> @@ -41,6 +35,7 @@ <version>${project.version}</version> <extensions>true</extensions> </plugin> + </plugins> </build> http://git-wip-us.apache.org/repos/asf/karaf-boot/blob/af6327ca/starters/karaf-boot-starter-jpa/pom.xml ---------------------------------------------------------------------- diff --git a/starters/karaf-boot-starter-jpa/pom.xml b/starters/karaf-boot-starter-jpa/pom.xml index c0ce5b8..734714b 100644 --- a/starters/karaf-boot-starter-jpa/pom.xml +++ b/starters/karaf-boot-starter-jpa/pom.xml @@ -1,23 +1,17 @@ <?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <!-- - - Licensed to the Apache Software Foundation (ASF) under one or more - contributor license agreements. See the NOTICE file distributed with - this work for additional information regarding copyright ownership. - The ASF licenses this file to You under the Apache License, Version 2.0 - (the "License"); you may not use this file except in compliance with - the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - --> + <!-- Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with this + work for additional information regarding copyright ownership. The ASF licenses + this file to You under the Apache License, Version 2.0 (the "License"); you + may not use this file except in compliance with the License. You may obtain + a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless + required by applicable law or agreed to in writing, software distributed + under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + OR CONDITIONS OF ANY KIND, either express or implied. See the License for + the specific language governing permissions and limitations under the License. --> <modelVersion>4.0.0</modelVersion> @@ -32,15 +26,36 @@ <dependencies> <dependency> - <groupId>org.osgi</groupId> - <artifactId>osgi.cmpn</artifactId> - <version>${osgi.version}</version> - </dependency> - <dependency> <groupId>org.apache.geronimo.specs</groupId> <artifactId>geronimo-jpa_2.0_spec</artifactId> <version>1.1</version> </dependency> + <!-- + <dependency> + <groupId>net.java.dev.stax-utils</groupId> + <artifactId>stax-utils</artifactId> + <version>20070216</version> + <exclusions> + <exclusion> + <artifactId>jsr173-ri</artifactId> + <groupId>com.bea.xml</groupId> + </exclusion> + </exclusions> + </dependency> + --> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <version>1.10.19</version> + <scope>test</scope> + </dependency> </dependencies> <build> http://git-wip-us.apache.org/repos/asf/karaf-boot/blob/af6327ca/starters/karaf-boot-starter-jpa/src/main/java/org/apache/karaf/boot/jpa/impl/JpaProcessor.java ---------------------------------------------------------------------- diff --git a/starters/karaf-boot-starter-jpa/src/main/java/org/apache/karaf/boot/jpa/impl/JpaProcessor.java b/starters/karaf-boot-starter-jpa/src/main/java/org/apache/karaf/boot/jpa/impl/JpaProcessor.java index 4becbc2..ed52850 100644 --- a/starters/karaf-boot-starter-jpa/src/main/java/org/apache/karaf/boot/jpa/impl/JpaProcessor.java +++ b/starters/karaf-boot-starter-jpa/src/main/java/org/apache/karaf/boot/jpa/impl/JpaProcessor.java @@ -1,27 +1,26 @@ package org.apache.karaf.boot.jpa.impl; -import javax.annotation.processing.AbstractProcessor; -import javax.annotation.processing.Messager; -import javax.annotation.processing.RoundEnvironment; -import javax.lang.model.element.AnnotationMirror; -import javax.lang.model.element.AnnotationValue; -import javax.lang.model.element.Element; -import javax.lang.model.element.TypeElement; -import javax.tools.Diagnostic.Kind; -import javax.tools.FileObject; -import javax.tools.StandardLocation; import java.io.IOException; -import java.io.PrintWriter; import java.io.Writer; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.tools.Diagnostic.Kind; +import javax.tools.FileObject; +import javax.tools.StandardLocation; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + import org.apache.karaf.boot.jpa.PersistentUnit; import org.apache.karaf.boot.jpa.Property; import org.apache.karaf.boot.jpa.Provider; @@ -41,76 +40,93 @@ public class JpaProcessor extends AbstractProcessor { @Override public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { Map<PersistentUnit, List<? extends AnnotationMirror>> units = new HashMap<PersistentUnit, List<? extends AnnotationMirror>>(); - - for (Element elem : roundEnv.getElementsAnnotatedWith(PersistentUnit.class)) { PersistentUnit pu = elem.getAnnotation(PersistentUnit.class); units.put(pu, elem.getAnnotationMirrors()); } if (!units.isEmpty()) { try { - Set<String> puNames = new HashSet<String>(); FileObject o = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, - "", "META-INF/persistence.xml"); - PrintWriter w = new PrintWriter(o.openWriter()); - w.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); - w.println("<persistence version=\"2.0\" xmlns=\"http://java.sun.com/xml/ns/persistence\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd\">"); - for (PersistentUnit pu : units.keySet()) { - if (pu.name() == null || pu.name().isEmpty()) { - throw new IOException("Missing persistent unit name"); - } - if (!puNames.add(pu.name())) { - throw new IOException("Duplicate persistent unit name: " + pu.name()); - } - w.println(" <persistence-unit name=\"" + pu.name() + "\" transaction-type=\"" + pu.transactionType().toString() + "\">"); - if (!pu.description().isEmpty()) { - w.println(" <description>" + pu.description() + "</description>"); - } - if (pu.provider() != Provider.Default || !pu.providerName().isEmpty()) { - if (pu.provider() != Provider.Default && !pu.providerName().isEmpty()) { - throw new IOException("At most one of provider and providerName can be used"); - } - String name; - if (!pu.providerName().isEmpty()) { - name = pu.providerName(); - } else { - switch (pu.provider()) { - case Hibernate: - name = "org.hibernate.jpa.HibernatePersistenceProvider"; - break; - default: - // TODO - throw new IOException("Unsupported provider: " + pu.provider()); - } - } - w.println(" <provider>" + name + "</provider>"); - } - if (!pu.jtaDataSource().isEmpty()) { - w.println(" <jta-data-source>" + pu.jtaDataSource() + "</jta-data-source>"); - } - if (!pu.nonJtaDataSource().isEmpty()) { - w.println(" <non-jta-data-source>" + pu.nonJtaDataSource() + "</non-jta-data-source>"); - } - if (pu.properties().length > 0) { - w.println(" <properties>"); - for (Property property : pu.properties()) { - w.println(" <property name=\"" + property.name() + "\" value=\"" + property.value() + "\"/>"); - } + "", "META-INF/persistence.xml"); + process(o.openWriter(), units); + processingEnv.getMessager().printMessage(Kind.NOTE, "Generated META-INF/persistence.xml"); + } catch (Exception e) { + processingEnv.getMessager().printMessage(Kind.ERROR, "Error: " + e.getMessage()); + } + } + return true; + } + + public void process(Writer writer, Map<PersistentUnit, List<? extends AnnotationMirror>> units) throws Exception { + Set<String> puNames = new HashSet<String>(); + XMLOutputFactory xof = XMLOutputFactory.newInstance(); + //XMLStreamWriter w = new IndentingXMLStreamWriter(xof.createXMLStreamWriter(writer)); + XMLStreamWriter w = xof.createXMLStreamWriter(writer); + w.setDefaultNamespace("http://java.sun.com/xml/ns/persistence"); + w.writeStartDocument(); + w.writeStartElement("persistence"); + w.writeAttribute("verson", "2.0"); + + //w.println("<persistence version=\"2.0\" xmlns=\"http://java.sun.com/xml/ns/persistence\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd\">"); + for (PersistentUnit pu : units.keySet()) { + if (pu.name() == null || pu.name().isEmpty()) { + throw new IOException("Missing persistent unit name"); + } + if (!puNames.add(pu.name())) { + throw new IOException("Duplicate persistent unit name: " + pu.name()); + } + w.writeStartElement("persistence-unit"); + w.writeAttribute("name", pu.name()); + w.writeAttribute("transaction-type", pu.transactionType().toString()); + writeElement(w, "description", pu.description()); + String providerName = getProvider(pu); + writeElement(w, "provider", providerName); + writeElement(w, "jta-data-source", pu.jtaDataSource()); + writeElement(w, "non-jta-data-source", pu.nonJtaDataSource()); + Map<String, String> props = new HashMap<>(); + addProperties(pu, props); + addAnnProperties(units.get(pu), props); + if (props.size() > 0) { + w.writeStartElement("properties"); + for (String key : props.keySet()) { + w.writeEmptyElement("property"); + w.writeAttribute("name", key); + w.writeAttribute("value", props.get(key)); + } + w.writeEndElement(); + } + w.writeEndElement(); + } + w.writeEndElement(); + w.writeEndDocument(); + w.flush(); + w.close(); + } + private void addProperties(PersistentUnit pu, Map<String, String> props) { + if (pu.properties() == null) { + return; + } + for (Property property : pu.properties()) { + props.put(property.name(), property.value()); + } + } - for (AnnotationMirror annMirror : units.get(pu)) { + private void addAnnProperties(List<? extends AnnotationMirror> annotations, Map<String, String> props) + throws XMLStreamException { + for (AnnotationMirror annMirror : annotations) { - String name = null; - for (AnnotationMirror a : processingEnv.getElementUtils().getAllAnnotationMirrors(annMirror.getAnnotationType().asElement())) { - if (a.toString().startsWith("@org.apache.karaf.boot.jpa.PersistentUnit.ProviderProperty")) { - name = a.getElementValues().values().iterator().next().getValue().toString(); - break; - } - } - if (name != null) { - String value = annMirror.getElementValues().values().iterator().next().getValue().toString(); - w.println(" <property name=\"" + name + "\" value=\"" + value + "\"/>"); - } + String name = null; + for (AnnotationMirror a : processingEnv.getElementUtils().getAllAnnotationMirrors(annMirror.getAnnotationType().asElement())) { + if (a.toString().startsWith("@org.apache.karaf.boot.jpa.PersistentUnit.ProviderProperty")) { + name = a.getElementValues().values().iterator().next().getValue().toString(); + break; + } + } + if (name != null) { + String value = annMirror.getElementValues().values().iterator().next().getValue().toString(); + props.put(name, value); + } // processingEnv.getMessager().printMessage(Kind.MANDATORY_WARNING, "Annotation: " + annMirror); // processingEnv.getMessager().printMessage(Kind.MANDATORY_WARNING, "Annotation type: " + annMirror.getAnnotationType()); // processingEnv.getMessager().printMessage(Kind.MANDATORY_WARNING, "Annotation annot: " + annMirror.getAnnotationType().getAnnotationMirrors()); @@ -121,20 +137,34 @@ public class JpaProcessor extends AbstractProcessor { // } else { // processingEnv.getMessager().printMessage(Kind.MANDATORY_WARNING, "Annotation nok"); // } - } + } + } - w.println(" </properties>"); - } - w.println(" </persistence-unit>"); - } - w.println("</persistence>"); - w.close(); - processingEnv.getMessager().printMessage(Kind.NOTE, "Generated META-INF/persistence.xml"); - } catch (IOException e) { - processingEnv.getMessager().printMessage(Kind.ERROR, "Error: " + e.getMessage()); + private void writeElement(XMLStreamWriter w, String localName, String content) throws XMLStreamException { + if (content != null && !content.isEmpty()) { + w.writeStartElement(localName); + w.writeCharacters(content); + w.writeEndElement(); + } + } + + private String getProvider(PersistentUnit pu) throws IOException { + if (pu.provider() != Provider.Default && pu.providerName() != null && !pu.providerName().isEmpty()) { + throw new IOException("At most one of provider and providerName can be used"); + } + if (pu.provider() != null) { + switch (pu.provider()) { + case Hibernate: + return "org.hibernate.jpa.HibernatePersistenceProvider"; + default: + // TODO + throw new IOException("Unsupported provider: " + pu.provider()); } + } else if (pu.providerName() != null) { + return pu.providerName(); + } else { + return null; } - return true; } } http://git-wip-us.apache.org/repos/asf/karaf-boot/blob/af6327ca/starters/karaf-boot-starter-jpa/src/test/java/org/apache/karaf/boot/jpa/impl/JpaProcessorTest.java ---------------------------------------------------------------------- diff --git a/starters/karaf-boot-starter-jpa/src/test/java/org/apache/karaf/boot/jpa/impl/JpaProcessorTest.java b/starters/karaf-boot-starter-jpa/src/test/java/org/apache/karaf/boot/jpa/impl/JpaProcessorTest.java new file mode 100644 index 0000000..d3e683a --- /dev/null +++ b/starters/karaf-boot-starter-jpa/src/test/java/org/apache/karaf/boot/jpa/impl/JpaProcessorTest.java @@ -0,0 +1,64 @@ +package org.apache.karaf.boot.jpa.impl; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.File; +import java.io.StringWriter; +import java.net.URL; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.lang.model.element.AnnotationMirror; + +import org.apache.karaf.boot.jpa.PersistentUnit; +import org.apache.karaf.boot.jpa.Property; +import org.apache.karaf.boot.jpa.Provider; +import org.apache.karaf.boot.jpa.TransactionType; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +public class JpaProcessorTest { + + @Ignore + @Test + public void testProcess() throws Exception { + JpaProcessor processor = new JpaProcessor(); + Map<PersistentUnit, List<? extends AnnotationMirror>> units = new HashMap<>(); + PersistentUnit pu = getTestPersitentUnit(); + units.put(pu, Collections.emptyList()); + URL url = this.getClass().getResource("/expected_persistence.xml"); + byte[] encoded = Files.readAllBytes(new File(url.toURI()).toPath()); + String expected = new String(encoded, Charset.forName("utf-8")); + StringWriter writer = new StringWriter(); + processor.process(writer, units); + Assert.assertEquals(expected, writer.getBuffer().toString()); + } + + private PersistentUnit getTestPersitentUnit() { + PersistentUnit pu = mock(PersistentUnit.class); + when(pu.name()).thenReturn("test-pu"); + when(pu.provider()).thenReturn(Provider.Hibernate); + when(pu.transactionType()).thenReturn(TransactionType.JTA); + when(pu.description()).thenReturn("Some description"); + when(pu.jtaDataSource()).thenReturn("myds"); + Property dialect = prop("hibernate.dialect", "org.hibernate.dialect.DerbyDialect"); + Property[] props = new Property[] { dialect }; + when(pu.properties()).thenReturn(props); + return pu; + } + + private Property prop(String name, String value) { + Property dialect = mock(Property.class); + when(dialect.name()).thenReturn(name); + when(dialect.value()).thenReturn(value); + return dialect; + } + + +} http://git-wip-us.apache.org/repos/asf/karaf-boot/blob/af6327ca/starters/karaf-boot-starter-jpa/src/test/resources/expected_persistence.xml ---------------------------------------------------------------------- diff --git a/starters/karaf-boot-starter-jpa/src/test/resources/expected_persistence.xml b/starters/karaf-boot-starter-jpa/src/test/resources/expected_persistence.xml new file mode 100644 index 0000000..8002eba --- /dev/null +++ b/starters/karaf-boot-starter-jpa/src/test/resources/expected_persistence.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" ?> +<persistence verson="2.0"> + <persistence-unit name="test-pu" transaction-type="JTA"> + <description>Some description</description> + <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> + <jta-data-source>myds</jta-data-source> + <properties> + <property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect"/> + </properties> + </persistence-unit> +</persistence>
