001/* 002 * Copyright 2010, 2011 Chris Pheby 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distringibuted under the License is distringibuted on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.jadira.bindings.core.general.binding; 017 018import java.lang.invoke.MethodHandle; 019import java.lang.invoke.MethodHandles; 020import java.lang.reflect.Method; 021import java.lang.reflect.Modifier; 022 023import org.jadira.bindings.core.api.Binding; 024import org.jadira.bindings.core.api.BindingException; 025import org.jadira.bindings.core.general.marshaller.MethodToMarshaller; 026 027/** 028 * Binding that supports a marshal contract, and a unmarshal method. The 029 * unmarshal method must be statically scoped. It must accept a single parameter 030 * of type S and return a type of T. For example: 031 * <p> 032 * {@code public static BoundType unmarshal(String string)} 033 * </p> 034 * @param <S> Source type for the conversion 035 * @param <T> Target type 036 */ 037public final class MethodsBinding<S, T> extends MethodToMarshaller<S, T> implements Binding<S, T> { 038 039 private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); 040 041 private final MethodHandle unmarshalHandle; 042 043 /** 044 * Constructs a binding that supports a marshal method and an unmarshal method 045 * @param marshal The marshalling method 046 * @param unmarshal The unmarshalling method 047 * @param boundClass The source class for unmarshalling from 048 * @param targetClass The target class for marshalling to 049 */ 050 public MethodsBinding(Method marshal, Method unmarshal, Class<S> boundClass, Class<T> targetClass) { 051 052 super(boundClass, targetClass, marshal); 053 054 if (unmarshal.getParameterTypes().length != 1) { 055 throw new IllegalStateException("unmarshal method must define a single parameter"); 056 } 057 if (!Modifier.isStatic(unmarshal.getModifiers())) { 058 throw new IllegalStateException("unmarshal method must be defined as static"); 059 } 060 061 if (unmarshal.getParameterTypes()[0] != targetClass) { 062 throw new IllegalStateException("unmarshal method must be parameterized by " + targetClass.getSimpleName()); 063 } 064 if (!boundClass.isAssignableFrom(unmarshal.getReturnType())) { 065 throw new IllegalStateException("unmarshal method must return " + boundClass.getSimpleName()); 066 } 067 068 try { 069 this.unmarshalHandle = LOOKUP.unreflect(unmarshal); 070 } catch (IllegalAccessException e) { 071 throw new IllegalStateException("Method is not accessible" + unmarshal); 072 } 073 } 074 075 /** 076 * {@inheritDoc} 077 */ 078 /* @Override */ 079 public S unmarshal(T string) { 080 081 try { 082 return getBoundClass().cast(unmarshalHandle.invoke(string)); 083 } catch (Throwable ex) { 084 if (ex.getCause() instanceof RuntimeException) { 085 throw (RuntimeException) ex.getCause(); 086 } 087 throw new BindingException(ex.getMessage(), ex.getCause()); 088 } 089 } 090}