TestScalaLikeImplicitProperties.java
package com.fasterxml.jackson.databind.introspect;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.testutil.DatabindTestUtil;
import static org.junit.jupiter.api.Assertions.*;
/**
* Tests Scala-style JVM naming patterns for properties.
*
* Scala uses identifiers that are legal JVM names, but not legal Java names:
*
* <ul>
* <li><code>prop���</code> (trailing space) for fields</li>
* <li><code>prop</code> for getters</li>
* <li><code>prop_=</code> for setters</li>
* </ul>
*
* Scala sources turn property accesses into method calls in most cases; the
* backing field and the particulars of the method names are implementation details.
*
* Since I can't reproduce them in Java, I've substituted legal but uncommonly
* used characters as placeholders.
*/
public class TestScalaLikeImplicitProperties extends DatabindTestUtil
{
static class NameMangler extends JacksonAnnotationIntrospector
{
private static final long serialVersionUID = 1L;
@Override
public String findImplicitPropertyName(AnnotatedMember member) {
String name = null;
if (member instanceof AnnotatedField) {
name = member.getName();
if (name.endsWith("���")) {
return name.substring(0, name.length()-1);
}
} else if (member instanceof AnnotatedMethod) {
name = member.getName();
if (name.endsWith("_���")) {
return name.substring(0, name.length()-2);
}
if (!name.startsWith("get") && !name.startsWith("set")) {
return name;
}
} else if (member instanceof AnnotatedParameter) {
// A placeholder for legitimate property name detection
// such as what the JDK8 module provides
return "prop";
}
return null;
}
/* Deprecated since 2.9
@Override
public boolean hasCreatorAnnotation(Annotated a) {
return (a instanceof AnnotatedConstructor);
}
*/
@Override
public JsonCreator.Mode findCreatorAnnotation(MapperConfig<?> config, Annotated a) {
// A placeholder for legitimate creator detection.
// In Scala, all primary constructors should be creators,
// but I can't obtain a reference to the AnnotatedClass from the
// AnnotatedConstructor, so it's simulated here.
return (a instanceof AnnotatedConstructor)
? JsonCreator.Mode.DEFAULT : null;
}
}
static class ValProperty
{
private final String prop���;
public String prop() { return prop���; }
public ValProperty(String prop) {
prop��� = prop;
}
}
static class ValWithBeanProperty
{
private final String prop���;
public String prop() { return prop���; }
public String getProp() { return prop���; }
public ValWithBeanProperty(String prop) {
prop��� = prop;
}
}
static class VarProperty
{
private String prop���;
public String prop() { return prop���; }
public void prop_���(String p) { prop��� = p; }
public VarProperty(String prop) {
prop��� = prop;
}
}
static class VarWithBeanProperty
{
private String prop���;
public String prop() { return prop���; }
public void prop_���(String p) { prop��� = p; }
public String getProp() { return prop���; }
public void setProp(String p) { prop��� = p; }
public VarWithBeanProperty(String prop) {
prop��� = prop;
}
}
static class GetterSetterProperty
{
// Different name to represent an arbitrary implementation, not necessarily local to this class.
private String _prop_impl = "get/set";
public String prop() { return _prop_impl; }
public void prop_���(String p) { _prop_impl = p; }
// Getter/Setters are typically not in the constructor because they are implemented
// by the end user, not the compiler. They should be detected similar to 'bean-style'
// getProp/setProp pairs.
}
/*
/**********************************************************
/* Test methods
/**********************************************************
*/
@Test
public void testValProperty() throws Exception
{
ObjectMapper m = manglingMapper();
assertEquals("{\"prop\":\"val\"}", m.writeValueAsString(new ValProperty("val")));
}
@Test
public void testValWithBeanProperty() throws Exception
{
ObjectMapper m = manglingMapper();
assertEquals("{\"prop\":\"val\"}", m.writeValueAsString(new ValWithBeanProperty("val")));
}
@Test
public void testVarProperty() throws Exception
{
ObjectMapper m = manglingMapper();
assertEquals("{\"prop\":\"var\"}", m.writeValueAsString(new VarProperty("var")));
VarProperty result = m.readValue("{\"prop\":\"read\"}", VarProperty.class);
assertEquals("read", result.prop());
}
@Test
public void testVarWithBeanProperty() throws Exception
{
ObjectMapper m = manglingMapper();
assertEquals("{\"prop\":\"var\"}", m.writeValueAsString(new VarWithBeanProperty("var")));
VarWithBeanProperty result = m.readValue("{\"prop\":\"read\"}", VarWithBeanProperty.class);
assertEquals("read", result.prop());
}
@Test
public void testGetterSetterProperty() throws Exception
{
ObjectMapper m = manglingMapper();
assertEquals("{\"prop\":\"get/set\"}", m.writeValueAsString(new GetterSetterProperty()));
GetterSetterProperty result = m.readValue("{\"prop\":\"read\"}", GetterSetterProperty.class);
assertEquals("read", result.prop());
}
/*
/**********************************************************
/* Helper methods
/**********************************************************
*/
private ObjectMapper manglingMapper()
{
ObjectMapper m = new ObjectMapper();
m.setAnnotationIntrospector(new NameMangler());
return m;
}
}