From c112063529baac332325fde0f2616e04dd073aee Mon Sep 17 00:00:00 2001 From: crazyboblee Date: Thu, 5 Feb 2009 06:23:52 +0000 Subject: Added XML example. git-svn-id: https://google-guice.googlecode.com/svn/trunk@831 d779f126-a31b-0410-b53b-1d3aecad763e --- examples/examples.iml | 23 +++ examples/src/example/xml/Contact.java | 5 + examples/src/example/xml/Contacts.java | 5 + examples/src/example/xml/FlashMemory.java | 10 ++ examples/src/example/xml/FromFlash.java | 7 + examples/src/example/xml/FromSim.java | 7 + examples/src/example/xml/Main.java | 48 ++++++ examples/src/example/xml/Phone.java | 14 ++ examples/src/example/xml/SimCard.java | 10 ++ examples/src/example/xml/XmlBeanModule.java | 227 ++++++++++++++++++++++++++++ examples/src/example/xml/phone.xml | 5 + lib/build/safesax.jar | Bin 0 -> 10055 bytes 12 files changed, 361 insertions(+) create mode 100644 examples/examples.iml create mode 100644 examples/src/example/xml/Contact.java create mode 100644 examples/src/example/xml/Contacts.java create mode 100644 examples/src/example/xml/FlashMemory.java create mode 100644 examples/src/example/xml/FromFlash.java create mode 100644 examples/src/example/xml/FromSim.java create mode 100644 examples/src/example/xml/Main.java create mode 100644 examples/src/example/xml/Phone.java create mode 100644 examples/src/example/xml/SimCard.java create mode 100644 examples/src/example/xml/XmlBeanModule.java create mode 100644 examples/src/example/xml/phone.xml create mode 100644 lib/build/safesax.jar diff --git a/examples/examples.iml b/examples/examples.iml new file mode 100644 index 00000000..9f903749 --- /dev/null +++ b/examples/examples.iml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/src/example/xml/Contact.java b/examples/src/example/xml/Contact.java new file mode 100644 index 00000000..160dbdcb --- /dev/null +++ b/examples/src/example/xml/Contact.java @@ -0,0 +1,5 @@ +package example.xml; + +public class Contact { + +} diff --git a/examples/src/example/xml/Contacts.java b/examples/src/example/xml/Contacts.java new file mode 100644 index 00000000..1efea32d --- /dev/null +++ b/examples/src/example/xml/Contacts.java @@ -0,0 +1,5 @@ +package example.xml; + +public interface Contacts { + Iterable findByName(String name); +} diff --git a/examples/src/example/xml/FlashMemory.java b/examples/src/example/xml/FlashMemory.java new file mode 100644 index 00000000..14294f44 --- /dev/null +++ b/examples/src/example/xml/FlashMemory.java @@ -0,0 +1,10 @@ +package example.xml; + +import java.util.Collections; + +public class FlashMemory implements Contacts { + + public Iterable findByName(String name) { + return Collections.emptyList(); + } +} diff --git a/examples/src/example/xml/FromFlash.java b/examples/src/example/xml/FromFlash.java new file mode 100644 index 00000000..def20447 --- /dev/null +++ b/examples/src/example/xml/FromFlash.java @@ -0,0 +1,7 @@ +package example.xml; + +import java.lang.annotation.Retention; +import static java.lang.annotation.RetentionPolicy.*; + +@Retention(RUNTIME) +public @interface FromFlash {} \ No newline at end of file diff --git a/examples/src/example/xml/FromSim.java b/examples/src/example/xml/FromSim.java new file mode 100644 index 00000000..47ed4164 --- /dev/null +++ b/examples/src/example/xml/FromSim.java @@ -0,0 +1,7 @@ +package example.xml; + +import java.lang.annotation.Retention; +import static java.lang.annotation.RetentionPolicy.*; + +@Retention(RUNTIME) +public @interface FromSim {} diff --git a/examples/src/example/xml/Main.java b/examples/src/example/xml/Main.java new file mode 100644 index 00000000..6983dec8 --- /dev/null +++ b/examples/src/example/xml/Main.java @@ -0,0 +1,48 @@ +/** + * Copyright (C) 2007 Google Inc. + * + * Licensed 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. + */ + +package example.xml; + +import com.google.inject.Guice; +import com.google.inject.AbstractModule; +import com.google.inject.Injector; +import java.net.URL; + +/** + * + * + */ +public class Main { + + public static void main(String[] args) { + final URL xmlUrl = Main.class.getResource("phone.xml"); + + Injector injector = Guice.createInjector(new AbstractModule() { + protected void configure() { + bind(Contacts.class).to(SimCard.class); + install(new XmlBeanModule(xmlUrl)); + } + }); + + Phone phone = injector.getInstance(Phone.class); + + if (phone.getContacts() == null) { + throw new AssertionError(); + } else { + System.out.println("It worked!"); + } + } +} diff --git a/examples/src/example/xml/Phone.java b/examples/src/example/xml/Phone.java new file mode 100644 index 00000000..a48ddcec --- /dev/null +++ b/examples/src/example/xml/Phone.java @@ -0,0 +1,14 @@ +package example.xml; + +public class Phone { + + Contacts contacts; + + public void setContacts(Contacts contacts) { + this.contacts = contacts; + } + + public Contacts getContacts() { + return contacts; + } +} diff --git a/examples/src/example/xml/SimCard.java b/examples/src/example/xml/SimCard.java new file mode 100644 index 00000000..71cf39bd --- /dev/null +++ b/examples/src/example/xml/SimCard.java @@ -0,0 +1,10 @@ +package example.xml; + +import java.util.Collections; + +public class SimCard implements Contacts { + + public Iterable findByName(String name) { + return Collections.emptyList(); + } +} \ No newline at end of file diff --git a/examples/src/example/xml/XmlBeanModule.java b/examples/src/example/xml/XmlBeanModule.java new file mode 100644 index 00000000..8701d68a --- /dev/null +++ b/examples/src/example/xml/XmlBeanModule.java @@ -0,0 +1,227 @@ +package example.xml; + +import com.google.inject.Key; +import com.google.inject.Module; +import com.google.inject.Provider; +import com.google.inject.Binder; +import java.io.InputStreamReader; +import java.io.Reader; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import org.xml.sax.Attributes; +import org.xml.sax.Locator; +import safesax.Element; +import safesax.ElementListener; +import safesax.Parsers; +import safesax.RootElement; +import safesax.StartElementListener; + +public class XmlBeanModule implements Module { + + final URL xmlUrl; + + Locator locator; + Binder originalBinder; + BeanBuilder beanBuilder; + + public XmlBeanModule(URL xmlUrl) { + this.xmlUrl = xmlUrl; + } + + public void configure(Binder binder) { + this.originalBinder = binder; + + try { + RootElement beans = new RootElement("beans"); + locator = beans.getLocator(); + + Element bean = beans.getChild("bean"); + bean.setElementListener(new BeanListener()); + + Element property = bean.getChild("property"); + property.setStartElementListener(new PropertyListener()); + + Reader in = new InputStreamReader(xmlUrl.openStream()); + Parsers.parse(in, beans.getContentHandler()); + } + catch (Exception e) { + originalBinder.addError(e); + } + } + + /** Handles "binding" elements. */ + class BeanListener implements ElementListener { + + public void start(final Attributes attributes) { + Binder sourced = originalBinder.withSource(xmlSource()); + + String typeString = attributes.getValue("type"); + + // Make sure 'type' is present. + if (typeString == null) { + sourced.addError("Missing 'type' attribute."); + return; + } + + // Resolve 'type'. + Class type; + try { + type = Class.forName(typeString); + } + catch (ClassNotFoundException e) { + sourced.addError(e); + return; + } + + // Look for a no-arg constructor. + try { + type.getConstructor(); + } + catch (NoSuchMethodException e) { + sourced.addError("%s doesn't have a no-arg constructor."); + return; + } + + // Create a bean builder for the given type. + beanBuilder = new BeanBuilder(type); + } + + public void end() { + if (beanBuilder != null) { + beanBuilder.build(); + beanBuilder = null; + } + } + } + + /** Handles "property" elements. */ + class PropertyListener implements StartElementListener { + + public void start(final Attributes attributes) { + Binder sourced = originalBinder.withSource(xmlSource()); + + if (beanBuilder == null) { + // We must have already run into an error. + return; + } + + // Check for 'name'. + String name = attributes.getValue("name"); + if (name == null) { + sourced.addError("Missing attribute name."); + return; + } + + Class type = beanBuilder.type; + + // Find setter method for the given property name. + String setterName = "set" + capitalize(name); + Method setter = null; + for (Method method : type.getMethods()) { + if (method.getName().equals(setterName)) { + setter = method; + break; + } + } + if (setter == null) { + sourced.addError("%s.%s() not found.", type.getName(), setterName); + return; + } + + // Validate number of parameters. + Type[] parameterTypes = setter.getGenericParameterTypes(); + if (parameterTypes.length != 1) { + sourced.addError("%s.%s() must take one argument.", + setterName, type.getName()); + return; + } + + // Add property descriptor to builder. + Provider provider = sourced.getProvider(Key.get(parameterTypes[0])); + beanBuilder.properties.add( + new Property(setter, provider)); + } + } + + static String capitalize(String s) { + return Character.toUpperCase(s.charAt(0)) + + s.substring(1); + } + + static class Property { + + final Method setter; + final Provider provider; + + Property(Method setter, Provider provider) { + this.setter = setter; + this.provider = provider; + } + + void setOn(Object o) { + try { + setter.invoke(o, provider.get()); + } + catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + catch (InvocationTargetException e) { + throw new RuntimeException(e); + } + } + } + + class BeanBuilder { + + final List properties = new ArrayList(); + final Class type; + + BeanBuilder(Class type) { + this.type = type; + } + + void build() { + addBinding(type); + } + + void addBinding(Class type) { + originalBinder.withSource(xmlSource()) + .bind(type).toProvider(new BeanProvider(type, properties)); + } + } + + static class BeanProvider implements Provider { + + final Class type; + final List properties; + + BeanProvider(Class type, List properties) { + this.type = type; + this.properties = properties; + } + + public T get() { + try { + T t = type.newInstance(); + for (Property property : properties) { + property.setOn(t); + } + return t; + } + catch (InstantiationException e) { + throw new RuntimeException(e); + } + catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + } + + Object xmlSource() { + return xmlUrl + ":" + locator.getLineNumber(); + } +} diff --git a/examples/src/example/xml/phone.xml b/examples/src/example/xml/phone.xml new file mode 100644 index 00000000..b14605e0 --- /dev/null +++ b/examples/src/example/xml/phone.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/lib/build/safesax.jar b/lib/build/safesax.jar new file mode 100644 index 00000000..e54b10c2 Binary files /dev/null and b/lib/build/safesax.jar differ -- cgit v1.2.3