I am very new to usage of annotation.
can anyone please tell me how can we declare an annotation and also call all the methods / variables that are declared with that annotation
am using java to implement this annotation
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
#Target(ElementType.FIELD)
public #interface isAnnotatedVariable {
String varName();
}
and used the annotation in
public class Example {
#isAnnotatedVariable(varName = "S")
public String var;
#isAnnotatedVariable(varName = "S")
public String var1;
}
and tried to get the variable names using
public class BuildStepClassDetector {
public static void main(String[] args) throws IOException {
BuildStepClassDetector build = new BuildStepClassDetector();
final Logger4J logger = new Logger4J(build.getClass().getName());
final HashMap<String, Class<?>> isAnnotatedVariables = new HashMap<String, Class<?>>();
final TypeReporter reporter = new TypeReporter() {
#SuppressWarnings("unchecked")
#Override
public Class<? extends Annotation>[] annotations() {
return new Class[] { isAnnotatedVariable.class };
}
#SuppressWarnings("unchecked")
#Override
public void reportTypeAnnotation(Class<? extends Annotation> arg0, String arg1) {
Class<? extends isAnnotatedVariable> isAnnotatedVariableClass;
try {
isAnnotatedVariableClass = (Class<? extends isAnnotatedVariable>) Class.forName(arg1);
isAnnotatedVariables.put(
isAnnotatedVariableClass.getAnnotation(isAnnotatedVariable.class).varName(),
isAnnotatedVariableClass);
} catch (ClassNotFoundException e) {
logger.getStackTraceString(e);
}
}
};
final AnnotationDetector cf = new AnnotationDetector(reporter);
cf.detect();
System.out.println(isAnnotatedVariables.keySet());
}
}
Here is a simple example for declaring annotation and retrieving a annotated field using Reflection.
package asif.hossain;
import java.lang.annotation.*;
import java.lang.reflect.Field;
/**
*
* Created by sadasidha on 21-Aug-14.
*/
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
#interface MyAnnotation {
public String value();
}
class TestClass
{
#MyAnnotation("This is a name field")
public String name;
}
public class Main {
public static void main(String ... args) throws IllegalAccessException {
TestClass testObject = new TestClass();
Field[] fields = testObject.getClass().getFields();
for (Field field : fields)
{
Annotation annotation = field.getAnnotation(MyAnnotation.class);
if(annotation instanceof MyAnnotation)
{
System.out.println(field.getName());
// get field value
String value = (String)field.get(testObject);
System.out.println("Field Value = "+ value);
//Set field value
field.set(testObject,"Your Name");
System.out.println(testObject.name);
}
}
}
}
You can follow this tutorial http://tutorials.jenkov.com/java-reflection/index.html to learn more about annotation and reflection.
Related
Using Jackson, is there a way to deserialize a proprty that depends on the value of another property?
if i have this json {"foo":"a","bar":"b"} i'd like to deserialize it to the Test class below as Test [foo=a, bar=b_a], where bar is the value of the json property "bar" and the value of the property "foo".
Of course this is a trivial example, the real deal would be to deserialize a datamodel entity: {"line":"C12", "machine": {"line":"C12", "code":"A"}} machine.line and line are always the same, and i'd like to express it like this: {"line":"C12", "machine": "A"}
import java.io.IOException;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
public abstract class Main{
private static class Test {
#JsonProperty
private String foo;
#JsonProperty
#JsonDeserialize(using = CustomDeserializer.class)
private String bar;
// ...other fields to be deserialized with default behaviour
private Test() {
}
public Test(String a, String bar) {
this.foo = a;
this.bar = bar;
}
#Override
public String toString() {
return "Test [foo=" + foo + ", bar=" + bar + "]";
}
}
private static class CustomDeserializer extends StdDeserializer<String> {
protected CustomDeserializer() {
super(String.class);
}
#Override
public String deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
String foo = //how to get foo property?
String value = p.getValueAsString();
if (!foo.isEmpty()) {
return value + "_" + foo;
} else {
return value;
}
}
}
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
Test foo2 = mapper.readValue("{\"foo\":\"a\",\"bar\":\"b\"}", Test.class);
System.out.println(foo2); // Test [foo=a, bar=b_a]
}
}
One way to solve your problem is specify a custom deserializer that involves your Test class instead of your string field because the deserialization of your property is based on the value of another property:
public class CustomDeserializer extends JsonDeserializer<Test> {}
#JsonDeserialize(using = CustomDeserializer.class)
public class Test {}
Then you can deserialize your object reading the JsonNode tree built from your input string:
public class CustomDeserializer extends JsonDeserializer<Test> {
#Override
public Test deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JsonProcessingException {
JsonNode node = jp.getCodec().readTree(jp);
String foo = node.get("foo").asText();
String bar = node.get("bar").asText();
if (!foo.isEmpty()) {
bar = (bar + '_' + foo);
}
return new Test(foo, bar);
}
}
//your example
public class Main {
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
Test foo2 = mapper.readValue("{\"foo\":\"a\",\"bar\":\"b\"}", Test.class);
System.out.println(foo2); // Test [foo=a, bar=b_a]
}
}
I got a similar problem today and I wanted to share my solution. So instead of using a #JsonDeserialize, I use a #JsonCreator on the parent object with a package private constructor to accept the "raw" properties and then I can process this data and return better objects.
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
class Scratch {
public static void main(String[] args) throws Exception{
final var testData = "{\"foo\":\"a\",\"bar\":\"b\"}";
final var mapper = new ObjectMapper();
final var testObj = mapper.readValue(testData, Test.class);
System.out.println(testObj); // Test[foo=a, bar=a_b]
}
record Test (
String foo,
String bar
){
#JsonCreator Test(
#JsonProperty("foo") String foo,
#JsonProperty("bar") String bar,
#JsonProperty("_dummy") String _dummy // extra param for the constructor overloading
) {
this(foo, deserializeBar(foo, bar));
}
private static String deserializeBar(String foo, String bar) {
if (foo == null || foo.isEmpty()) {
return bar;
}
return "%s_%s".formatted(foo, bar);
}
}
}
In the end, I've resorted using BeanDeserializerModifier
Please notice that the following code is not fully functioning because it relies on code I'm not allowed to share, but it should suffice to get the idea.
package com.example;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.scanners.TypeAnnotationsScanner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.deser.BeanDeserializer;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
public class JsonDelegateDeserializerModule extends SimpleModule {
// !! must be registered as guice factory
public interface JsonDelegateDeserializerFactory {
JsonDelegateDeserializerModule create(String packagePath);
}
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface JsonDelegateDeserializer {
public Class<? extends StdDeserializer<?>> deserializer();
public Class<?> forType();
}
protected interface JsonDeserializerFactory {
// non metto nessun generic in TagHandler o guice non riesce piu a creare la
// factory!
#SuppressWarnings("rawtypes")
public JsonDeserializer create(JsonDeserializer baseDeserializer);
}
private static final Logger LOGGER = LoggerFactory.getLogger(JsonDelegateDeserializerModule.class);
#Inject
private FactoryInjector injector;
private final String packagePath;
#AssistedInject
protected JsonDelegateDeserializerModule(#Assisted String packagePath) {
super();
this.packagePath = packagePath;
}
#Override
public String getModuleName() {
return JsonDelegateDeserializerModule.class.getSimpleName() + "[" + packagePath + "]";
}
#Override
public Object getTypeId() {
return JsonDelegateDeserializerModule.class.getSimpleName() + "[" + packagePath + "]";
}
#Override
public void setupModule(SetupContext context) {
Reflections reflectios = new Reflections(packagePath, new SubTypesScanner(), new TypeAnnotationsScanner());
Map<Class<?>, JsonDeserializerFactory> classToDeserializerFactory = new HashMap<>();
Set<Class<?>> classesWithModifier = reflectios.getTypesAnnotatedWith(JsonDelegateDeserializer.class);
for (Class<?> classWithModifier : classesWithModifier) {
JsonDelegateDeserializer annotation = classWithModifier.getAnnotation(JsonDelegateDeserializer.class);
if (annotation != null) {
Class<? extends StdDeserializer<?>> deserializerType = annotation.deserializer();
Class<?> forType = annotation.forType();
try {
JsonDeserializerFactory factory = injector.getFactory(JsonDeserializerFactory.class,
deserializerType);
classToDeserializerFactory.put(forType, factory);
} catch (Exception e) {
LOGGER.error("Exception was thown while creating deserializer {} for type {}:", deserializerType,
forType, e);
throw new RuntimeException(e);
}
}
}
if (!classToDeserializerFactory.isEmpty()) {
setDeserializerModifier(new BeanDeserializerModifier() {
#Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc,
JsonDeserializer<?> deserializer) {
List<Class<?>> possibleTypesList = new LinkedList<>();
if (deserializer instanceof BeanDeserializer) {
for (Entry<Class<?>, JsonDeserializerFactory> entry : classToDeserializerFactory.entrySet()) {
Class<?> type = entry.getKey();
if (type.isAssignableFrom(deserializer.handledType())) {
possibleTypesList.add(type);
}
}
if (possibleTypesList.size() > 1) {
possibleTypesList.sort(new Comparator<Class<?>>() {
#Override
public int compare(Class<?> o1, Class<?> o2) {
if (o1.isAssignableFrom(o2)) {
return 1;
} else {
return -1;
}
}
});
}
Class<?> type = Utils.first(possibleTypesList);
if (type == null) {
return super.modifyDeserializer(config, beanDesc, deserializer);
} else {
JsonDeserializerFactory factory = classToDeserializerFactory.get(type);
JsonDeserializer<?> modifiedDeserializer = factory.create(deserializer);
return super.modifyDeserializer(config, beanDesc, modifiedDeserializer);
}
} else {
// รจ gia stato impostato un deserializzatore piu specifico, non imposato questo
return super.modifyDeserializer(config, beanDesc, deserializer);
}
}
});
}
super.setupModule(context);
}
}
then you can simply annotate the Mixin to add the custom deserializer
#JsonDelegateDeserializer(deserializer = LoadLineDeserializer.class, forType = Line.class)
public interface LineMixIn {
public static class LoadLineDeserializer extends DelegatingDeserializer {
#AssistedInject
public LoadLineDeserializer(#Assisted JsonDeserializer baseDeserializer, LineService lineService) {
super(baseDeserializer);
}
// ...
}
// ...
}
I am trying to map a non-iterable value i.e. String to a list of string using mapstruct.
So I am using
#Mapping(target = "abc", expression = "java(java.util.Arrays.asList(x.getY().getXyz()))")
Here abc is List<String>
xyz is a String
But for this i need to check for null explicitly.
Is there any better way of maaping a non-iterable to iterable by converting non iterable to iterable.
Here is an example for non iterable-to-iterable:
public class Source {
private String myString;
public String getMyString() {
return myString;
}
public void setMyString(String myString) {
this.myString = myString;
}
}
public class Target {
private List<String> myStrings;
public List<String> getMyStrings() {
return myStrings;
}
public void setMyStrings(List<String> myStrings) {
this.myStrings = myStrings;
}
}
#Qualifier
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.SOURCE)
public #interface FirstElement {
}
public class NonIterableToIterableUtils {
#FirstElement
public List<String> first(String in ) {
if (StringUtils.isNotEmpty(in)) {
return Arrays.asList(in);
} else {
return null;
}
}
}
#Mapper( uses = NonIterableToIterableUtils.class )
public interface SourceTargetMapper {
SourceTargetMapper MAPPER = Mappers.getMapper( SourceTargetMapper.class );
#Mappings( {
#Mapping( source = "myString", target = "myStrings", qualifiedBy = FirstElement.class )
} )
Target toTarget( Source s );
}
public class Main {
public static void main(String[] args) {
Source s = new Source();
s.setMyString("Item");
Target t = SourceTargetMapper.MAPPER.toTarget( s );
System.out.println( t.getMyStrings().get(0));
}
}
There is a iterable-to-non-iterable example in the MapStruct examples repository. Addtionally there is a pending pull request for non-iterable-to-iterable.
In a nutshell you can use a custom method that would do the mapping. You can also use #Qualifier to have more granural control
Add an empty default method in the mapper, e.g. AnimalMapper.toLions(), and overwrite the default method in a mapper decorator, e.g. AnimalMapperDecorator. It works in my test.
#Repository
#Mapper(componentModel = "spring")
#DecoratedWith(AnimalMapperDecorator.class)
public interface AnimalMapper {
default List<Lion> toLions(Jungle jungle) {
return null;
}
}
public abstract class AnimalMapperDecorator implements AnimalMapper {
#Autowired
#Qualifier("delegate")
private AnimalMapper delegate;
#Override
public List<Lion> toLions(Jungle jungle) {
List<Lion> lions = new ArrayList<>();
Lion king = getKing(jungle);
Lion queen = getQueen(jungle);
Lion leo = getLeo(jungle);
lions.add(king); lions.add(queen); lions.add(leo);
return lions;
}
}
class Test {
#Autowired
private AnimalMapper animalMapper;
public void test() {
Jungle jungle = generateJungle();
List<Lion> lions = animalMapper.toLions(jungle);
// Assert lions
}
}
I'm reviewing how reflection works or possible work. I have this SomeClassBuilder wherein it has an attribute target : Target with declared annotation TargetAnnotation.
Thing is, is it possible to override/update the values/properties of Target wherein upon invoke of someMethod() would return the parameters on the annotation?
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface TargetAnnotation {
String first();
String second();
// other attributes
}
public class Target {
String first;
String second;
// some other attributes unique only to `Target`
}
public interface TargetHelper {
void setTarget(Target target);
}
public class SomeClassBuilder implements TargetHelper {
#TargetAnnotation(first = "first", second = "second")
private Target target;
#Override public void setTarget(Target target) { this.target = target }
public void someMethod() {
System.out.println(target.first); // should be `first`
System.out.println(target.second); // should be `second`
}
}
Or is it even possible to do it without TargetHelper interface?
Let's say I have this TargetProcessor called before SomeClassBuilder which sole purpose is to fill-in the target : Target annotated with #TargetAnnotation and assign the field/attributes from #TargetAnnotaton to Target.
public class TargetProcessor {
public void parse() {
// look into `#TargetAnnotation`
// map `#TargetAnnotation` properties to `Target`
}
}
You can achieve this by implementing Annotation Processor for your annotation #TargetAnnotation
For further readings and examples:
http://www.baeldung.com/java-annotation-processing-builder
https://github.com/bozaro/example-annotation-processor/blob/master/example-modify/processor/src/main/java/ru/bozaro/processor/HelloProcessor.java
https://deors.wordpress.com/2011/10/08/annotation-processors/
This article explains, how it should be done:
http://hannesdorfmann.com/annotation-processing/annotationprocessing101
Here is my code
import static xdean.jex.util.lang.ExceptionUtil.uncheck;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;
import java.util.stream.Stream;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import xdean.jex.util.reflect.ReflectUtil;
public class Q46765735 {
public static void main(String[] args) {
create(TargetDomain.class).printTarget();
}
public static <T> T create(Class<T> clz) {
T target = uncheck(() -> clz.newInstance());
Stream.of(ReflectUtil.getAllFields(clz, false)).forEach(f -> uncheck(() -> fill(target, f)));
return target;
}
private static <T> void fill(T target, Field field) throws Exception {
TargetAnnotation anno = field.getAnnotation(TargetAnnotation.class);
if (anno == null) {
return;
}
Class<?> type = field.getType();
if (!Target.class.isAssignableFrom(type)) {
return;
}
field.setAccessible(true);
Target value = (Target) field.get(target);
if (value == null) {
value = (Target) type.newInstance();
}
value.setFirst(anno.first());
value.setSecond(anno.second());
field.set(target, value);
}
}
#Retention(RetentionPolicy.RUNTIME)
#java.lang.annotation.Target({ ElementType.FIELD })
#interface TargetAnnotation {
String first();
String second();
}
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
class Target {
String first;
String second;
}
class TargetDomain {
#TargetAnnotation(first = "first", second = "second")
private Target target = new Target("a", "b");
public void printTarget() {
System.out.println(target.first); // should be `first`
System.out.println(target.second); // should be `second`
}
}
Tips:
You can replace lombok by write constructor and getter/setter manually.
ReflectUtil.getAllFields get all fields of the class.
uncheck simply ignore exceptions, you can use try-catch.
I created a simple annotation class:
#Retention(RUNTIME)
public #interface Column {
public String name();
}
I use it in some classes like this:
public class FgnPzt extends Point {
public static final String COLUMN_TYPE = "type";
#Column(name=COLUMN_TYPE)
protected String type;
}
I know that I can iterate over the declared fields and obtain the annotation like this:
for (Field field : current.getDeclaredFields()) {
try {
Column c = field.getAnnotation(Column.class);
[...]
} catch(Exception e) {
[...]
}
}
How can I obtain the field type directly by its annotated name without iterating over declared fields of the class?
If you need to make multiple accesses you can pre-process the annotations.
public class ColumnExtracter<T> {
private final Map<String, Field> fieldsByColumn;
public ColumnExtracter(Class<T> clazz) {
this.fieldsByColumn = Stream.of(clazz.getDeclaredFields())
.filter(field -> field.isAnnotationPresent(Column.class))
.collect(Collectors.toMap(field -> field.getAnnotation(Column.class).name(), Function.identity()));
}
public Field getColumnField(String columnName) {
return fieldsByColumn.get(columnName);
}
public <R> R extract(String columnName, T t, Class<R> clazz) throws IllegalAccessException {
return clazz.cast(extract(columnName, t));
}
public Object extract(String columnName, T t) throws IllegalAccessException {
return getColumnField(columnName).get(t);
}
}
I would like to use the generic type safe container pattern, described in Joshua Bloch's Effective Java, but would like to restrict the classes which can be used as keys by using an enum. Below is the code from Joshua's book.
public class Favorites {
private Map<Class<?>, Object> favorites = new HashMap<Class<?>, Object>();
public <T> void putFavorite(Class<T> type, T instance) {
if (type == null)
throw new NullPointerException("Type is null");
favorites.put(type, instance);
}
public <T> T getFavorite(Class<T> type) {
return type.cast(favorites.get(type));
}
}
I would like to write a similar class, but limit the keys to say "Dog.class", and "Cat.class". Ideally, the acceptable keys would be described by an enum, and the "RestrictedFavorites" class would take members of the enum as keys. I'm not sure if I can get the compiler to do all these things for me (type safety, restriction by enum, generality), but if anybody has a suggestion, I'm all ears. Below is attempt V1, which uses runtime checks rather than compile time checks, and is not entirely satisfactory.
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Attempt V1 At a "RestrictedFavorites" class
*/
public class RestrictedFavorites {
public static enum RestrictedKey {
STRING(String.class),
INTEGER(Integer.class);
private static Set<Class<?>> classes;
static {
classes = new HashSet<>();
for (RestrictedKey key: values()) {
classes.add(key.getKlass());
}
}
private final Class<?> klass;
RestrictedKey(Class<?> klass) {
this.klass = klass;
}
public Class<?> getKlass() {
return klass;
}
public static boolean isValidClassKey(Class<?> klass) {
return classes.contains(klass);
}
}
private Map<Class<?>, Object> favorites = new HashMap<Class<?>, Object>();
//Ideally would use compile time checking
public <T> void putFavorite(RestrictedKey key, T instance) {
if (key == null) throw new NullPointerException("Type is null");
if (!key.getKlass().equals(instance.getClass())) {
throw new IllegalArgumentException(
"The type of the key must match the type of the instance");
}
favorites.put(key.getKlass(), instance);
}
//Ideally would take a RestrictedKey as an argument
public <T> T getFavorite(Class<T> key) {
if (!RestrictedKey.isValidClassKey(key)) {
throw new IllegalArgumentException(
"The key must be a member of RestrictedKeys");
}
return key.cast(favorites.get(key));
}
}
Below are some unit tests to verify that my class is doing roughly what I want it to:
public class RestrictedFavoritesTest extends TestCase {
public void testPutFavorite() {
RestrictedFavorites myFavorites = new RestrictedFavorites();
myFavorites.putFavorite(RestrictedKey.INTEGER, 1);
myFavorites.putFavorite(RestrictedKey.STRING, "hey");
int expectedInt = myFavorites.getFavorite(Integer.class);
assertEquals(1, expectedInt);
String expectedString = myFavorites.getFavorite(String.class);
assertEquals("hey", expectedString);
}
public void testPutFavorite_wrongType() {
RestrictedFavorites myFavorites = new RestrictedFavorites();
try {
myFavorites.putFavorite(RestrictedKey.INTEGER, "hey");
fail();
} catch (IllegalArgumentException expected) {}
}
public void testPutFavorite_wrongClass() {
RestrictedFavorites myFavorites = new RestrictedFavorites();
try {
myFavorites.getFavorite(Boolean.class);
} catch (IllegalArgumentException expected) {}
}
}
Answer (to my own question). Don't use Enums. Because enums can't be generic. Instead, create a class to represent the restricted keys, and restrict access to the constructor. Enumerate the valid keys as fields.
import java.util.HashMap;
import java.util.Map;
public class RestrictedFavorites {
private static final class RestrictedKey<T> {
private final Class<T> type;
private RestrictedKey(Class<T> type) {
this.type = type;
}
private Class<T> getMyType() {
return this.type;
}
}
public static final RestrictedKey<String> STRING_KEY =
new RestrictedKey<>(String.class);
public static final RestrictedKey<Integer> INTEGER_KEY =
new RestrictedKey<>(Integer.class);
private final Map<RestrictedKey<?>, Object> favorites =
new HashMap<RestrictedKey<?>, Object>();
public <T> void putFavorite(RestrictedKey<T> key, T instance) {
favorites.put(key, instance);
}
public <T> T getFavorite(RestrictedKey<T> key) {
return key.getMyType().cast(favorites.get(key));
}
}
And the unit tests:
public class RestrictedFavoritesTest extends TestCase {
public void testPutFavorite() {
RestrictedFavorites myFavorites = new RestrictedFavorites();
myFavorites.putFavorite(RestrictedFavorites.STRING_KEY, "hey");
myFavorites.putFavorite(RestrictedFavorites.INTEGER_KEY, 1);
assertEquals(new Integer(1), myFavorites.getFavorite(RestrictedFavorites.INTEGER_KEY));
assertEquals("hey", myFavorites.getFavorite(RestrictedFavorites.STRING_KEY));
}
}