Browse Source
* changed default query encoder result from POJO field to getter property * changed default query encoder result from POJO field to getter property * reset mistakenly deleted file * Create PropertyQueryMapEncoder and extract QueryMapEncoder.Default to FieldQueryMapEncoder * rename PropertyQueryMapEncoder to BeanQueryMapEncoder and add README * fix README * add comments to QueryMapEncoder and remove deprecation on Default * rename test name * rename package name queryMap to querymap * format codepull/795/head
王灿
6 years ago
committed by
Marvin Froeder
8 changed files with 429 additions and 78 deletions
@ -0,0 +1,85 @@
@@ -0,0 +1,85 @@
|
||||
/** |
||||
* Copyright 2012-2018 The Feign Authors |
||||
* |
||||
* 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 feign.querymap; |
||||
|
||||
import feign.QueryMapEncoder; |
||||
import feign.codec.EncodeException; |
||||
import java.beans.IntrospectionException; |
||||
import java.beans.Introspector; |
||||
import java.beans.PropertyDescriptor; |
||||
import java.lang.reflect.InvocationTargetException; |
||||
import java.util.*; |
||||
|
||||
/** |
||||
* the query map will be generated using java beans accessible getter property as query parameter |
||||
* names. |
||||
* |
||||
* eg: "/uri?name={name}&number={number}" |
||||
* |
||||
* order of included query parameters not guaranteed, and as usual, if any value is null, it will be |
||||
* left out |
||||
*/ |
||||
public class BeanQueryMapEncoder implements QueryMapEncoder { |
||||
private final Map<Class<?>, ObjectParamMetadata> classToMetadata = |
||||
new HashMap<Class<?>, ObjectParamMetadata>(); |
||||
|
||||
@Override |
||||
public Map<String, Object> encode(Object object) throws EncodeException { |
||||
try { |
||||
ObjectParamMetadata metadata = getMetadata(object.getClass()); |
||||
Map<String, Object> propertyNameToValue = new HashMap<String, Object>(); |
||||
for (PropertyDescriptor pd : metadata.objectProperties) { |
||||
Object value = pd.getReadMethod().invoke(object); |
||||
if (value != null && value != object) { |
||||
propertyNameToValue.put(pd.getName(), value); |
||||
} |
||||
} |
||||
return propertyNameToValue; |
||||
} catch (IllegalAccessException | IntrospectionException | InvocationTargetException e) { |
||||
throw new EncodeException("Failure encoding object into query map", e); |
||||
} |
||||
} |
||||
|
||||
private ObjectParamMetadata getMetadata(Class<?> objectType) throws IntrospectionException { |
||||
ObjectParamMetadata metadata = classToMetadata.get(objectType); |
||||
if (metadata == null) { |
||||
metadata = ObjectParamMetadata.parseObjectType(objectType); |
||||
classToMetadata.put(objectType, metadata); |
||||
} |
||||
return metadata; |
||||
} |
||||
|
||||
private static class ObjectParamMetadata { |
||||
|
||||
private final List<PropertyDescriptor> objectProperties; |
||||
|
||||
private ObjectParamMetadata(List<PropertyDescriptor> objectProperties) { |
||||
this.objectProperties = Collections.unmodifiableList(objectProperties); |
||||
} |
||||
|
||||
private static ObjectParamMetadata parseObjectType(Class<?> type) |
||||
throws IntrospectionException { |
||||
List<PropertyDescriptor> properties = new ArrayList<PropertyDescriptor>(); |
||||
|
||||
for (PropertyDescriptor pd : Introspector.getBeanInfo(type).getPropertyDescriptors()) { |
||||
boolean isGetterMethod = pd.getReadMethod() != null && !"class".equals(pd.getName()); |
||||
if (isGetterMethod) { |
||||
properties.add(pd); |
||||
} |
||||
} |
||||
|
||||
return new ObjectParamMetadata(properties); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,79 @@
@@ -0,0 +1,79 @@
|
||||
/** |
||||
* Copyright 2012-2018 The Feign Authors |
||||
* |
||||
* 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 feign.querymap; |
||||
|
||||
import feign.QueryMapEncoder; |
||||
import feign.codec.EncodeException; |
||||
import java.lang.reflect.Field; |
||||
import java.util.*; |
||||
|
||||
/** |
||||
* the query map will be generated using member variable names as query parameter names. |
||||
* |
||||
* eg: "/uri?name={name}&number={number}" |
||||
* |
||||
* order of included query parameters not guaranteed, and as usual, if any value is null, it will be |
||||
* left out |
||||
*/ |
||||
public class FieldQueryMapEncoder implements QueryMapEncoder { |
||||
|
||||
private final Map<Class<?>, ObjectParamMetadata> classToMetadata = |
||||
new HashMap<Class<?>, ObjectParamMetadata>(); |
||||
|
||||
@Override |
||||
public Map<String, Object> encode(Object object) throws EncodeException { |
||||
try { |
||||
ObjectParamMetadata metadata = getMetadata(object.getClass()); |
||||
Map<String, Object> fieldNameToValue = new HashMap<String, Object>(); |
||||
for (Field field : metadata.objectFields) { |
||||
Object value = field.get(object); |
||||
if (value != null && value != object) { |
||||
fieldNameToValue.put(field.getName(), value); |
||||
} |
||||
} |
||||
return fieldNameToValue; |
||||
} catch (IllegalAccessException e) { |
||||
throw new EncodeException("Failure encoding object into query map", e); |
||||
} |
||||
} |
||||
|
||||
private ObjectParamMetadata getMetadata(Class<?> objectType) { |
||||
ObjectParamMetadata metadata = classToMetadata.get(objectType); |
||||
if (metadata == null) { |
||||
metadata = ObjectParamMetadata.parseObjectType(objectType); |
||||
classToMetadata.put(objectType, metadata); |
||||
} |
||||
return metadata; |
||||
} |
||||
|
||||
private static class ObjectParamMetadata { |
||||
|
||||
private final List<Field> objectFields; |
||||
|
||||
private ObjectParamMetadata(List<Field> objectFields) { |
||||
this.objectFields = Collections.unmodifiableList(objectFields); |
||||
} |
||||
|
||||
private static ObjectParamMetadata parseObjectType(Class<?> type) { |
||||
List<Field> fields = new ArrayList<Field>(); |
||||
for (Field field : type.getDeclaredFields()) { |
||||
if (!field.isAccessible()) { |
||||
field.setAccessible(true); |
||||
} |
||||
fields.add(field); |
||||
} |
||||
return new ObjectParamMetadata(fields); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,50 @@
@@ -0,0 +1,50 @@
|
||||
/** |
||||
* Copyright 2012-2018 The Feign Authors |
||||
* |
||||
* 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 feign; |
||||
|
||||
public class PropertyPojo { |
||||
|
||||
private String name; |
||||
|
||||
public static class ChildPojoClass extends PropertyPojo { |
||||
private Integer number; |
||||
|
||||
private String privateGetterProperty; |
||||
|
||||
public Integer getNumber() { |
||||
return number; |
||||
} |
||||
|
||||
public void setNumber(Integer number) { |
||||
this.number = number; |
||||
} |
||||
|
||||
public void setPrivateGetterProperty(String privateGetterProperty) { |
||||
this.privateGetterProperty = privateGetterProperty; |
||||
} |
||||
|
||||
private String getPrivateGetterProperty() { |
||||
return privateGetterProperty; |
||||
} |
||||
} |
||||
|
||||
public String getName() { |
||||
return name; |
||||
} |
||||
|
||||
public void setName(String name) { |
||||
this.name = name; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,130 @@
@@ -0,0 +1,130 @@
|
||||
/** |
||||
* Copyright 2012-2018 The Feign Authors |
||||
* |
||||
* 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 feign.querymap; |
||||
|
||||
import feign.QueryMapEncoder; |
||||
import org.junit.Rule; |
||||
import org.junit.Test; |
||||
import org.junit.rules.ExpectedException; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.junit.Assert.assertTrue; |
||||
|
||||
public class PropertyQueryMapEncoderTest { |
||||
|
||||
@Rule |
||||
public final ExpectedException thrown = ExpectedException.none(); |
||||
|
||||
private final QueryMapEncoder encoder = new BeanQueryMapEncoder(); |
||||
|
||||
@Test |
||||
public void testDefaultEncoder_normalClassWithValues() { |
||||
Map<String, Object> expected = new HashMap<>(); |
||||
expected.put("foo", "fooz"); |
||||
expected.put("bar", "barz"); |
||||
expected.put("fooAppendBar", "foozbarz"); |
||||
NormalObject normalObject = new NormalObject("fooz", "barz"); |
||||
|
||||
Map<String, Object> encodedMap = encoder.encode(normalObject); |
||||
|
||||
assertEquals("Unexpected encoded query map", expected, encodedMap); |
||||
} |
||||
|
||||
@Test |
||||
public void testDefaultEncoder_normalClassWithOutValues() { |
||||
NormalObject normalObject = new NormalObject(null, null); |
||||
|
||||
Map<String, Object> encodedMap = encoder.encode(normalObject); |
||||
|
||||
assertTrue("Non-empty map generated from null getter: " + encodedMap, encodedMap.isEmpty()); |
||||
} |
||||
|
||||
@Test |
||||
public void testDefaultEncoder_haveSuperClass() { |
||||
Map<String, Object> expected = new HashMap<>(); |
||||
expected.put("page", 1); |
||||
expected.put("size", 10); |
||||
expected.put("query", "queryString"); |
||||
SubClass subClass = new SubClass(); |
||||
subClass.setPage(1); |
||||
subClass.setSize(10); |
||||
subClass.setQuery("queryString"); |
||||
|
||||
Map<String, Object> encodedMap = encoder.encode(subClass); |
||||
|
||||
assertEquals("Unexpected encoded query map", expected, encodedMap); |
||||
} |
||||
|
||||
|
||||
class NormalObject { |
||||
|
||||
private NormalObject(String foo, String bar) { |
||||
this.foo = foo; |
||||
this.bar = bar; |
||||
} |
||||
|
||||
private String foo; |
||||
private String bar; |
||||
|
||||
public String getFoo() { |
||||
return foo; |
||||
} |
||||
|
||||
public String getBar() { |
||||
return bar; |
||||
} |
||||
|
||||
public String getFooAppendBar() { |
||||
if (foo != null && bar != null) { |
||||
return foo + bar; |
||||
} |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
class SuperClass { |
||||
private int page; |
||||
private int size; |
||||
|
||||
public int getPage() { |
||||
return page; |
||||
} |
||||
|
||||
public void setPage(int page) { |
||||
this.page = page; |
||||
} |
||||
|
||||
public int getSize() { |
||||
return size; |
||||
} |
||||
|
||||
public void setSize(int size) { |
||||
this.size = size; |
||||
} |
||||
} |
||||
|
||||
class SubClass extends SuperClass { |
||||
|
||||
private String query; |
||||
|
||||
public String getQuery() { |
||||
return query; |
||||
} |
||||
|
||||
public void setQuery(String query) { |
||||
this.query = query; |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue