Spring data neo4j embedded property MappingException - spring

I am fairly new to Neo4J; I am developing a project for learning purposes on which I am facing an issue that I am not managing to solve. My model might be somewhat relational DB influenced, but design issues aside, I believe however that what I am attempting should technically be done.
I have a NodeEntity Foo with an nested object Bar, converted to- and from String via ConversionService. In effect, Bar contains only one single String field, making the mapping trivial.
#NodeEntity
public class Foo {
#GraphId
private Long id;
#Indexed
private Bar bar;
...
}
public class Bar {
private String value;
...
}
When returning from a fairly simple Cypher query defined as follows on my repository:
#RepositoryRestResource(...)
public interface FooRepository
extends PagingAndSortingRepository<Foo, Long> {
...
#Query ("MATCH (foo) RETURN foo.bar")
Iterable<Bar> listBars ();
...
}
Conversion is configured as follows:
#Configuration
#ComponentScan(value = "de.h7r.playground.sd.neo4j",
excludeFilters = #ComponentScan.Filter({ Configuration.class }))
public class PKanbanConfiguration {
#Bean
public ConversionServiceFactoryBean conversionService ()
throws Exception {
final ConversionServiceFactoryBean csfb = new ConversionServiceFactoryBean ();
csfb.setConverters (getConverters ());
return csfb;
}
private Set<Converter> getConverters () {
return Sets.newHashSet (new BarConverter.ToString (), new BarConverter.FromString ());
}
}
Where the code for BarConverter is as follows.
public class BarConverter {
public static class FromString <S extends String, P extends Bar>
implements Converter<S, P> {
#Override
public P convert (final S source) {
// sets value into new instance of Bar and returns
}
}
public static class ToString <P extends Bar, S extends String>
implements Converter<P, S> {
#Override
public S convert (final P source) {
// gets value from Bar and returns
}
}
}
I am getting the following exception.
org.springframework.data.mapping.model.MappingException: Unknown persistent entity test.domain.Bar
at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:178)
...
Bar is indeed not a persitent entity nor should in my understanding be one. I grasp that this might have something to do with the defined return type of listBars; on the other hand, the repository if of Foos, so I had expected it to work. I would very much not like to fetch the whole set of nodes and then filter only the nested objects; the same way I would not like to have Bar replaced by String on Foo, since their type might have semantic relevance.
I am a bit lost as to how to returning all the property values for the existing nodes, specially since this query works as expected from neo4j-shell, so I see this as a pure Spring mapping issue.
I can add any further information that might prove helpful upon request.
Any help is very much appreciated.

Related

Two-way binding in Android with data from Room database

I am new to the MVVM architecture in Android, and I have some days with a doubt that I consider basic, but that I can't solve.
I proceed to discuss my problem:
I have an Entity, CustomerView (this entity is created from a DatabaseView):
#DatabaseView("select ... ")
public class CustomerView {
public String cardCode;
public String cardName;
public String cardFName;
...
Then, I have a Dao class:
#Dao
public interface OCRD_DAO {
...
#Query("SELECT * from CustomerView where cardCode= :cardCode")
LiveData<CustomerView> getCustomerViewByCardCode(String cardCode);
...
}
The repository class, makes use of the DAO class:
public LiveData<CustomerView> getCustomer(String cardCode){
return mOcrdDao.getCustomerViewByCardCode(cardCode);
}
The CustomerSheetViewModel class:
public class CustomerSheetViewModel extends BaseObservable {
private Repository mRepository;
public LiveData<CustomerView> mCustomer;
private MutableLiveData<String> _cardName;
#Bindable
public MutableLiveData<String> getCardName(){
return this._cardName;
}
public MutableLiveData<String> setCardName(String value){
// Avoids infinite loops.
if (mCustomer.getValue().cardName != value) {
mCustomer.getValue().cardName = value;
// React to the change.
saveData();
// Notify observers of a new value.
notifyPropertyChanged(BR._cardName);
}
}
public CustomerSheetViewModel (Application application, String cardCode) {
mRepository = new Repository(application);
this.mCustomer = mRepository.getCustomer(cardCode);
//Init MutableLiveData????
this._cardName = this.mCustomer.getValue().cardName;
//Null Exception, because this.mCustomer.getValue() is null
}
}
At this point, my problem occurs: when I initialise the CustomerView object, it is of type LiveData. However, if I want to make use of 2-way binding, I need an object of type MutableLiveData. So, I think I should create the MutableLiveData object with the data extracted from the database (i.e. from the call to the repository). When I try this (e.g. getValue().cardName) a null exception is thrown, since LiveData is asynchronous.
Finally, I could make use of this property in the layout:
android:text="#={customerSheetViewModel.cardName}"
I really appreciate any help, as I can't find any reference to 2-way binding when the data comes from a database read.
Thanks in advance.

resolveContextualObject and getConversationId in custom Spring scope

I am wondering what is the purpose of org.springframework.beans.factory.config.Scope.resolveContextualObject(String key) and org.springframework.beans.factory.config.Scope.getConversationId()?
From the javadoc:
Object resolveContextualObject(String key)
Resolve the contextual object for the given key, if any. E.g. the HttpServletRequest object for key "request".
String getConversationId()
Return the conversation ID for the current underlying scope, if any.
The exact meaning of the conversation ID depends on the underlying storage mechanism. In the case of session-scoped objects, the conversation ID would typically be equal to (or derived from) the session ID; in the case of a custom conversation that sits within the overall session, the specific ID for the current conversation would be appropriate.
This description doesn't tell me much.
Could you give me some examples which demonstrate how to make use of these methods?
My observation is that resolveContextualObject(String key) looks like a code smell, where where a Scope can expose some internal object.
Having:
public class MyCustomScope implements Scope {
private Pair<String, String> myPair;
#Override
public Object resolveContextualObject(String key) {
if ("myKey".equals(key)) return myPair;
return null;
}
// ...
}
#Configuration
public class RegisterMyScopeConfig {
#Bean
public BeanFactoryPostProcessor beanFactoryPostProcessor() {
return beanFactory -> beanFactory.registerScope(
"mycustomscope", new MyCustomScope());
}
}
Then you can:
#Scope("mycustomscope")
#Component
class MyComponent {
#Value("#{myKey.first}")
private String firstOfMyPair;
// or
#Value("#{myKey}")
private Pair<String,String> myPair;
}
Of course the way how you resolved object which matches key, might be fancier ;).
For example, in GenericScope it looks like that:
#Override
public Object resolveContextualObject(String key) {
Expression expression = parseExpression(key);
return expression.getValue(this.evaluationContext, this.beanFactory);
}

Jackson #JsonFilter is not getting applied when used at field or method level

I am using Spring version 4.3.3 and Jackson version 2.8.3. I am trying to filter out specific fields from an entity bean based on some custom logic that is determined at runtime. The #JsonFilter seems ideal for this type of functionality. The problem is that when I put it at the field or method level, my custom filter never gets invoked. If I put it at the class level, it gets invoked just fine. I don't want to use it at the class level though since then I would need to separately maintain the list of hardcoded field names that I want to apply the logic to. As of Jackson 2.3, the ability to put this annotation at the field level is supposed to exist.
Here is the most basic custom filter without any custom logic yet:
public class MyFilter extends SimpleBeanPropertyFilter {
#Override
protected boolean include(BeanPropertyWriter beanPropertyWriter) {
return true;
}
#Override
protected boolean include(PropertyWriter propertyWriter) {
return true;
}
}
Then I have the Jackson ObjectMapper configuration:
public class MyObjectMapper extends ObjectMapper {
public MyObjectMapper () {
SimpleFilterProvider filterProvider = new SimpleFilterProvider();
filterProvider.addFilter("myFilter", new MyFilter());
setFilterProvider(filterProvider);
}
}
Then finally I have my entity bean:
#Entity
public class Project implements Serializable {
private Long id;
private Long version;
#JsonFilter("myFilter") private String name;
#JsonFilter("myFilter") private String description;
// getters and setters
}
If I move the #JsonFilter annotation to the class level where #Entity is, the filter at least gets invoked, but when it is at the field level like in the example here, it never gets invoked.
I have the same need but after examining the unit tests I discovered that this is not the use-case covered by annotating a field.
Annotating a field invokes a filter on the value of the field not the instance containing the field. For example, imagine you have to classes, A and B, where A contains a field of type B.
class A {
#JsonFilter("myFilter") B foo;
}
Jackson applies "myFilter" to the fields in B not in A. Since your example contains fields of type String, which has no fields, Jackson never invokes your filter.
I have a need to exclude certain fields based on the caller's permissions. For example, an employee's profile may contain his taxpayer id, which is considered sensitive information and should only be serialized if the caller is a member of the Payrole department. Since I'm using Spring Security, I wish to integrate Jackson with the current security context.
public class EmployeeProfile {
private String givenName;
private String surname;
private String emailAddress;
#VisibleWhen("hasRole('PayroleSpecialist')")
private String taxpayerId;
}
The most obvious way to do this is to Jackson's filter mechanism but it has a few limitations:
Jackson does not support nested filters so adding an access filter prohibits using filters for any other purpose.
One cannot add Jackson annotations to existing, third-party classes.
Jackson filters are not designed to be generic. The intent is to write a custom filter for each class you wish to apply filtering. For example, I you need to filter classes A and B, then you have to write an AFilter and a BFilter.
For my use-case, the solution is to use a custom annotation introspector in conjunction with a chaining filter.
public class VisibilityAnnotationIntrospector extends JacksonAnnotationIntrospector {
private static final long serialVersionUID = 1L;
#Override
public Object findFilterId(Annotated a) {
Object result = super.findFilterId(a);
if (null != result) return result;
// By always returning a value, we cause Jackson to query the filter provider.
// A more sophisticated solution will introspect the annotated class and only
// return a value if the class contains annotated properties.
return a instanceof AnnotatedClass ? VisibilityFilterProvider.FILTER_ID : null;
}
}
This is basically a copy SimpleBeanProvider that replaces calls to include with calls to isVisible. I'll probably update this to use a Java 8 BiPredicate to make the solution more general but works for now.
This class also takes another filter as an argument and will delegate to it the final decision on whether to serialize the field if the field is visible.
public class AuthorizationFilter extends SimpleBeanPropertyFilter {
private final PropertyFilter antecedent;
public AuthorizationFilter() {
this(null);
}
public AuthorizationFilter(final PropertyFilter filter) {
this.antecedent = null != filter ? filter : serializeAll();
}
#Deprecated
#Override
public void serializeAsField(Object bean, JsonGenerator jgen, SerializerProvider provider, BeanPropertyWriter writer) throws Exception {
if (isVisible(bean, writer)) {
this.antecedent.serializeAsField(bean, jgen, provider, writer);
} else if (!jgen.canOmitFields()) { // since 2.3
writer.serializeAsOmittedField(bean, jgen, provider);
}
}
#Override
public void serializeAsField(Object pojo, JsonGenerator jgen, SerializerProvider provider, PropertyWriter writer) throws Exception {
if (isVisible(pojo, writer)) {
this.antecedent.serializeAsField(pojo, jgen, provider, writer);
} else if (!jgen.canOmitFields()) { // since 2.3
writer.serializeAsOmittedField(pojo, jgen, provider);
}
}
#Override
public void serializeAsElement(Object elementValue, JsonGenerator jgen, SerializerProvider provider, PropertyWriter writer) throws Exception {
if (isVisible(elementValue, writer)) {
this.antecedent.serializeAsElement(elementValue, jgen, provider, writer);
}
}
private static boolean isVisible(Object pojo, PropertyWriter writer) {
// Code to determine if the field should be serialized.
}
}
I then add a custom filter provider to each instance of ObjectMapper.
#SuppressWarnings("deprecation")
public class VisibilityFilterProvider extends SimpleFilterProvider {
private static final long serialVersionUID = 1L;
static final String FILTER_ID = "dummy-filter-id";
#Override
public BeanPropertyFilter findFilter(Object filterId) {
return super.findFilter(filterId);
}
#Override
public PropertyFilter findPropertyFilter(Object filterId, Object valueToFilter) {
if (FILTER_ID.equals(filterId)) {
// This implies that the class did not have an explict filter annotation.
return new AuthorizationFilter(null);
}
// The class has an explicit filter annotation so delegate to it.
final PropertyFilter antecedent = super.findPropertyFilter(filterId, valueToFilter);
return new VisibilityPropertyFilter(antecedent);
}
}
Finally, I have a Jackson module that automatically registers the custom annotaion introspector so I don't have to add it to each ObjectMapper instance manually.
public class FieldVisibilityModule extends SimpleModule {
private static final long serialVersionUID = 1L;
public FieldVisibilityModule() {
super(PackageVersion.VERSION);
}
#Override
public void setupModule(Module.SetupContext context) {
super.setupModule(context);
// Append after other introspectors (instead of before) since
// explicit annotations should have precedence
context.appendAnnotationIntrospector(new VisibilityAnnotationIntrospector());
}
}
There are more improvements that can be made and I still have more unit tests to write (e.g., handling arrays and collections) but this is the basic strategy I used.
You can try this approach for the same purpose:
#Entity
#Inheritance(
strategy = InheritanceType.SINGLE_TABLE
)
#DiscriminatorColumn(
discriminatorType = DiscriminatorType.STRING,
length = 2
)
#Table(
name = "project"
)
#JsonTypeInfo(
use = Id.CLASS,
include = As.PROPERTY,
property = "#class"
)
#JsonSubTypes({
#Type(
value = BasicProject.class,
name = "basicProject"
),
#Type(
value = AdvanceProject.class,
name = "advanceProject"
)})
public abstract class Project {
private Long id;
private Long version;
}
#Entity
#DiscriminatorValue("AD")
public class AdvanceProject extends Project {
private String name;
private String description;
}
#Entity
#DiscriminatorValue("BS")
public class BasicProject extends Project {
private String name;
}
I don't think you will make it work. I was trying and these are results of my investigation, maybe it will be helpful.
First of all, as #Faron noticed, the #JsonFilterannotation is applied for the class being annotated not a field.
Secondly, I see things this way. Let's imagine, somewhere in Jackson internals you are able to get the actual field. You can figure out if there is the annotation using Java Reflection API. You can even get the filter name. Then you get to the filter and pass the field value there. But it happens at runtime, how will you get the corresponding JsonSerializer of the field type if you decide to serialize the field? It is impossible because of type erasure.
The only alternative I see is to forget about dynamic logic. Then you can do the following things:
1) extend JacksonAnnotationIntrospector (almost the same as implement AnnotationIntrospector but no useless default code) overriding hasIgnoreMarker method. Take a look at this answer
2) criminal starts here. Kinda weird way taking into account your initial goal but still: extend BeanSerializerModifier and filter out fields there. An example can be found here. This way you can define serializer that actually doesn't serialize anything (again, I understand how strange it is but maybe one will find it helpful)
3) similar to the approach above: define useless serializer based on BeanDescription implementing ContextualSerializer's createContextual method. The example of this magic is here
Thanks to this really good blog, I was able to use #JsonView to filter out specific fields from an entity bean based on some custom logic that is determined at runtime.
Since the #JsonFilter does not apply for the fields within a class, I found this to be a cleaner workaround.
Here is the sample code:
#Data
#AllArgsConstructor
public class TestEntity {
private String a;
#JsonView(CustomViews.SecureAccess.class)
private Date b;
#JsonView(CustomViews.SecureAccess.class)
private Integer c;
private List<String> d;
}
public class CustomViews {
public static interface GeneralAccess {}
public static interface SecureAccess {}
public static class GeneralAccessClass implements GeneralAccess {}
public static class SecureAccessClass implements SecureAccess, GeneralAccess {}
public static Class getWriterView(final boolean hasSecureAccess) {
return hasSecureAccess
? SecureAccessClass.class
: GeneralAccessClass.class;
}
}
#Test
public void test() throws JsonProcessingException {
final boolean hasSecureAccess = false; // Custom logic resolved to a boolean value at runtime.
final TestEntity testEntity = new TestEntity("1", new Date(), 2, ImmutableList.of("3", "4", "5"));
final ObjectMapper objectMapper = new ObjectMapper().enable(MapperFeature.DEFAULT_VIEW_INCLUSION);
final String serializedValue = objectMapper
.writerWithView(CustomViews.getWriterView(hasSecureAccess))
.writeValueAsString(testEntity);
Assert.assertTrue(serializedValue.contains("a"));
Assert.assertFalse(serializedValue.contains("b"));
Assert.assertFalse(serializedValue.contains("c"));
Assert.assertTrue(serializedValue.contains("d"));
}

How do I mock an autowired #Value field in Spring with Mockito?

I'm using Spring 3.1.4.RELEASE and Mockito 1.9.5. In my Spring class I have:
#Value("#{myProps['default.url']}")
private String defaultUrl;
#Value("#{myProps['default.password']}")
private String defaultrPassword;
// ...
From my JUnit test, which I currently have set up like so:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({ "classpath:test-context.xml" })
public class MyTest
{
I would like to mock a value for my "defaultUrl" field. Note that I don't want to mock values for the other fields — I'd like to keep those as they are, only the "defaultUrl" field. Also note that I have no explicit "setter" methods (e.g. setDefaultUrl) in my class and I don't want to create any just for the purposes of testing.
Given this, how can I mock a value for that one field?
You can use the magic of Spring's ReflectionTestUtils.setField in order to avoid making any modifications whatsoever to your code.
The comment from Michał Stochmal provides an example:
use ReflectionTestUtils.setField(bean, "fieldName", "value"); before invoking your bean method during test.
Check out this tutorial for even more information, although you probably won't need it since the method is very easy to use
UPDATE
Since the introduction of Spring 4.2.RC1 it is now possible to set a static field without having to supply an instance of the class. See this part of the documentation and this commit.
It was now the third time I googled myself to this SO post as I always forget how to mock an #Value field. Though the accepted answer is correct, I always need some time to get the "setField" call right, so at least for myself I paste an example snippet here:
Production class:
#Value("#{myProps[‘some.default.url']}")
private String defaultUrl;
Test class:
import org.springframework.test.util.ReflectionTestUtils;
ReflectionTestUtils.setField(instanceUnderTest, "defaultUrl", "http://foo");
// Note: Don't use MyClassUnderTest.class, use the instance you are testing itself
// Note: Don't use the referenced string "#{myProps[‘some.default.url']}",
// but simply the FIELDs name ("defaultUrl")
You can use this magic Spring Test annotation :
#TestPropertySource(properties = { "my.spring.property=20" })
see
org.springframework.test.context.TestPropertySource
For example, this is the test class :
#ContextConfiguration(classes = { MyTestClass.Config.class })
#TestPropertySource(properties = { "my.spring.property=20" })
public class MyTestClass {
public static class Config {
#Bean
MyClass getMyClass() {
return new MyClass ();
}
}
#Resource
private MyClass myClass ;
#Test
public void myTest() {
...
And this is the class with the property :
#Component
public class MyClass {
#Value("${my.spring.property}")
private int mySpringProperty;
...
I'd like to suggest a related solution, which is to pass the #Value-annotated fields as parameters to the constructor, instead of using the ReflectionTestUtils class.
Instead of this:
public class Foo {
#Value("${foo}")
private String foo;
}
and
public class FooTest {
#InjectMocks
private Foo foo;
#Before
public void setUp() {
ReflectionTestUtils.setField(Foo.class, "foo", "foo");
}
#Test
public void testFoo() {
// stuff
}
}
Do this:
public class Foo {
private String foo;
public Foo(#Value("${foo}") String foo) {
this.foo = foo;
}
}
and
public class FooTest {
private Foo foo;
#Before
public void setUp() {
foo = new Foo("foo");
}
#Test
public void testFoo() {
// stuff
}
}
Benefits of this approach: 1) we can instantiate the Foo class without a dependency container (it's just a constructor), and 2) we're not coupling our test to our implementation details (reflection ties us to the field name using a string, which could cause a problem if we change the field name).
You can also mock your property configuration into your test class
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({ "classpath:test-context.xml" })
public class MyTest
{
#Configuration
public static class MockConfig{
#Bean
public Properties myProps(){
Properties properties = new Properties();
properties.setProperty("default.url", "myUrl");
properties.setProperty("property.value2", "value2");
return properties;
}
}
#Value("#{myProps['default.url']}")
private String defaultUrl;
#Test
public void testValue(){
Assert.assertEquals("myUrl", defaultUrl);
}
}
I used the below code and it worked for me:
#InjectMocks
private ClassABC classABC;
#Before
public void setUp() {
ReflectionTestUtils.setField(classABC, "constantFromConfigFile", 3);
}
Reference: https://www.jeejava.com/mock-an-autowired-value-field-in-spring-with-junit-mockito/
Also note that I have no explicit "setter" methods (e.g. setDefaultUrl) in my class and I don't want to create any just for the purposes of testing.
One way to resolve this is change your class to use Constructor Injection, that can be used for testing and Spring injection. No more reflection :)
So, you can pass any String using the constructor:
class MySpringClass {
private final String defaultUrl;
private final String defaultrPassword;
public MySpringClass (
#Value("#{myProps['default.url']}") String defaultUrl,
#Value("#{myProps['default.password']}") String defaultrPassword) {
this.defaultUrl = defaultUrl;
this.defaultrPassword= defaultrPassword;
}
}
And in your test, just use it:
MySpringClass MySpringClass = new MySpringClass("anyUrl", "anyPassword");
Whenever possible, I set the field visibility as package-protected so it can be accessed from the test class. I document that using Guava's #VisibleForTesting annotation (in case the next guy wonders why it's not private). This way I don't have to rely on the string name of the field and everything stays type-safe.
I know it goes against standard encapsulation practices we were taught in school. But as soon as there is some agreement in the team to go this way, I found it the most pragmatic solution.
Another way is to use #SpringBootTest annotation properties field.
Here we override example.firstProperty property:
#SpringBootTest(properties = { "example.firstProperty=annotation" })
public class SpringBootPropertySourceResolverIntegrationTest {
#Autowired private PropertySourceResolver propertySourceResolver;
#Test
public void shouldSpringBootTestAnnotation_overridePropertyValues() {
String firstProperty = propertySourceResolver.getFirstProperty();
String secondProperty = propertySourceResolver.getSecondProperty();
Assert.assertEquals("annotation", firstProperty);
Assert.assertEquals("defaultSecond", secondProperty);
}
}
As you can see It overrides only one property. Properties not mentioned in #SpringBootTest stay untouched. Therefore, this is a great solution when we need to override only specific properties for the test.
For single property you can write it without braces:
#SpringBootTest(properties = "example.firstProperty=annotation")
Answer from: https://www.baeldung.com/spring-tests-override-properties#springBootTest
I also encourage you to whenever possible pass property as a parameter in constructor like in Dherik answer (https://stackoverflow.com/a/52955459/1673775) as it enables you to mock properties easily in unit tests.
However in integration tests you often don't create objects manually, but:
you use #Autowired
you want to modify property used in a class that is used in your integration test indirectly as it is deep dependency of some directly used class.
then this solution with #SpringBootTest might be helpful.

Gson.toJson() and inheriting from a generic class

I have the following class:
public static class TestSomething {
Integer test;
public TestSomething(Integer test) {
this.test = test;
}
// getter and setter for test
}
Ok, now create a collection of this class and serialize it with Gson:
Collection<TestSomething> tests = Arrays.asList(
new TestSomething(1),
new TestSomething(2),
new TestSomething(3)
);
String json = new Gson().toJson(tests, new TypeToken<Collection<TestSomething>>() {}.getType());
After this, the String json is set to
[{"test":1},{"test":2},{"test":3}]
Which is great.
But now, all of my model classes inherit from a generic type Identifiable<T> which provides just two methods T getId() and void setId(T). So I change the TestSomething-class from above to
public static class TestSomething extends Identifiable<Long> {
// same as above
}
When I try to put this through Gson.toJson(), Gson ends up with the following Exception:
java.lang.UnsupportedOperationException: Expecting parameterized type, got class path.to.TestSomething.
Are you missing the use of TypeToken idiom?
See http://sites.google.com/site/gson/gson-user-guide#TOC-Serializing-and-Deserializing-Gener
at com.google.gson.TypeInfoFactory.getActualType(TypeInfoFactory.java:97)
...
So, what do I have to do to get this work?
I don't know the answer, but I know that generic type resolution is a tricky thing to get right: specifically full type resolution from interface with type parameter T up through to generic parameter declaration (T=Long). In these cases it is not enough to check for Method object's parameters but also resolve generic type parameters. This is most likely what causes issues; it may be a bug in Gson.
Since you are serializing things, perhaps you could just omit any type declarations? Although your TypeToken is correct for the use case, maybe it confuses Gson.
But just in case you could not make Gson work with this, I know that of other JSON libraries Jackson can handle such cases correctly.
Perhaps this issue was resolved in one of the Gson releases newer than what the original questioner was using, because the example in the original question now serializes as expected.
// output:
// [{"test":1},{"test":2},{"test":3}]
import java.util.Arrays;
import java.util.Collection;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
public class Foo
{
public static void main(String[] args)
{
Collection<TestSomething> tests = Arrays.asList(
new TestSomething(1),
new TestSomething(2),
new TestSomething(3));
String json = new Gson().toJson(tests, new TypeToken<Collection<TestSomething>>() {}.getType());
System.out.println(json);
}
}
class TestSomething extends Identifiable<Long>
{
Integer test;
public TestSomething(Integer test)
{
this.test = test;
}
#Override
Long getId()
{
return new Long(test);
}
#Override
void setId(Long t)
{
this.test = (int)(t.longValue());
}
}
abstract class Identifiable<T>
{
abstract T getId();
abstract void setId(T t);
}

Resources