Skip to content

Commit

Permalink
Fixed issue #119 OpenPojo able to construct non static nested classes…
Browse files Browse the repository at this point in the history
… correctly.
  • Loading branch information
oshoukry committed Jan 26, 2019
1 parent 217f794 commit c506923
Show file tree
Hide file tree
Showing 6 changed files with 210 additions and 12 deletions.
38 changes: 27 additions & 11 deletions src/main/java/com/openpojo/reflection/impl/PojoMethodImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
import java.util.Arrays;
import java.util.List;

import com.openpojo.reflection.PojoClass;
import com.openpojo.reflection.PojoMethod;
import com.openpojo.reflection.PojoParameter;
import com.openpojo.reflection.exception.ReflectionException;
Expand Down Expand Up @@ -107,8 +106,8 @@ public List<PojoParameter> getPojoParameters() {

if (isConstructor()) {
parameterAnnotations = getAsConstructor().getParameterAnnotations();
parameterTypes = getConstructorGenericParameterTypes(getAsConstructor());
parameterClasses = getAsConstructor().getParameterTypes();
parameterTypes = getConstructorGenericParameterTypes(getAsConstructor(), parameterClasses);
} else {
parameterAnnotations = getAsMethod().getParameterAnnotations();
parameterTypes = getAsMethod().getGenericParameterTypes();
Expand Down Expand Up @@ -186,20 +185,37 @@ public Class<?>[] getParameterTypes() {
return getAsMethod().getParameterTypes();
}

private Type[] getConstructorGenericParameterTypes(Constructor<?> asConstructor) {
private Type[] getConstructorGenericParameterTypes(Constructor<?> asConstructor, Class<?>[] parameterClasses) {
Type[] genericParameterTypes = asConstructor.getGenericParameterTypes();

//See: http://bugs.java.com/view_bug.do?bug_id=5087240
PojoClass pojoClass = PojoClassFactory.getPojoClass(getAsConstructor().getDeclaringClass());
Class<?> declaringClass = asConstructor.getDeclaringClass();
genericParameterTypes = bug_5087240_workaround(declaringClass, genericParameterTypes, parameterClasses);

if (pojoClass.isNestedClass() && !pojoClass.isStatic()) {
Type[] fixedGenericParameterTypes = new Type[genericParameterTypes.length + 1];
fixedGenericParameterTypes[0] = pojoClass.getClazz();
System.arraycopy(genericParameterTypes, 0, fixedGenericParameterTypes, 1, genericParameterTypes.length);
genericParameterTypes = fixedGenericParameterTypes;
return genericParameterTypes;
}

/**
* See: http://bugs.java.com/view_bug.do?bug_id=5087240
*/
private Type[] bug_5087240_workaround(Class<?> clazz, Type[] genericParameterTypes,
Class<?>[] parameterClasses) {
Type[] fixedGenericParameterType = genericParameterTypes;

if (isNestedNonStaticClass(clazz) && missingSyntheticParameter(genericParameterTypes, parameterClasses)) {
fixedGenericParameterType = new Type[parameterClasses.length];
fixedGenericParameterType[0] = parameterClasses[0];
System.arraycopy(genericParameterTypes, 0, fixedGenericParameterType, 1, genericParameterTypes.length);
}

return genericParameterTypes;
return fixedGenericParameterType;
}

private boolean missingSyntheticParameter(Type[] genericParameterTypes, Class<?>[] parameterClasses) {
return (genericParameterTypes.length + 1) == parameterClasses.length;
}

private boolean isNestedNonStaticClass(Class<?> clazz) {
return clazz.getEnclosingClass() != null && !Modifier.isStatic(clazz.getModifiers());
}

public Class<?> getReturnType() {
Expand Down
52 changes: 52 additions & 0 deletions src/test/java/com/openpojo/issues/issue119/IssueTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright (c) 2010-2019 Osman Shoukry
*
* 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 com.openpojo.issues.issue119;

import java.util.List;

import com.openpojo.reflection.PojoClass;
import com.openpojo.validation.Validator;
import com.openpojo.validation.ValidatorBuilder;
import com.openpojo.validation.rule.impl.GetterMustExistRule;
import com.openpojo.validation.rule.impl.SetterMustExistRule;
import com.openpojo.validation.test.impl.GetterTester;
import com.openpojo.validation.test.impl.SetterTester;
import org.junit.Assert;
import org.junit.Test;

import static com.openpojo.reflection.impl.PojoClassFactory.*;
import static org.hamcrest.CoreMatchers.is;

public class IssueTest {

@Test
public void shouldTestAllClasses() {
Validator validator = ValidatorBuilder.create()
.with(new GetterMustExistRule())
.with(new SetterMustExistRule())
.with(new GetterTester())
.with(new SetterTester())
.build();

List<PojoClass> classes = getPojoClassesRecursively(this.getClass().getPackage().getName() + ".sample", null);

Assert.assertThat(classes.size(), is(3));
validator.validate(classes);
}
}
68 changes: 68 additions & 0 deletions src/test/java/com/openpojo/issues/issue119/sample/Outer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright (c) 2010-2019 Osman Shoukry
*
* 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 com.openpojo.issues.issue119.sample;

import java.util.List;

@SuppressWarnings("unused")
public class Outer {
private String outerName;

public String getOuterName() {
return outerName;
}

public void setOuterName(String outerName) {
this.outerName = outerName;
}

public class Level1Inner {
private String level1InnerName;

private Level1Inner(String level1InnerName) {
this.level1InnerName = level1InnerName;
}

public String getLevel1InnerName() {
return level1InnerName;
}

public void setLevel1InnerName(String level1InnerName) {
this.level1InnerName = level1InnerName;
}

public class Level2Inner {
private String level2InnerName;

private Level2Inner(List<String> names) {
if (names.size() > 0)
level2InnerName = names.get(0);
}

public String getLevel2InnerName() {
return level2InnerName;
}

public void setLevel2InnerName(String level2InnerName) {
this.level2InnerName = level2InnerName;
}

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@
import java.util.LinkedList;
import java.util.List;

import com.openpojo.random.RandomFactory;
import com.openpojo.reflection.PojoClass;
import com.openpojo.reflection.PojoMethod;
import com.openpojo.reflection.PojoParameter;
import com.openpojo.reflection.impl.sample.classes.AClassWithGenericParameterConstructor;
import com.openpojo.reflection.impl.sample.classes.AClassWithGenericParameterMethod;
import com.openpojo.reflection.impl.sample.classes.AClassWithNestedClass;
import com.openpojo.validation.affirm.Affirm;
import org.junit.Test;

Expand Down Expand Up @@ -84,4 +87,49 @@ public void shouldGetMethodWithGenericParameter() {

}

@Test
public void shouldHaveOneParameterForInstanceNestedClassWhenNoneDeclared() {
PojoClass pojoclass = PojoClassFactory.getPojoClass(AClassWithNestedClass.NestedClass.class);
List<PojoMethod> pojoConstructors = pojoclass.getPojoConstructors();
Affirm.affirmEquals("Should have only one constructor", 1, pojoConstructors.size());
PojoMethod constructor = pojoConstructors.get(0);
List<PojoParameter> pojoParameters = constructor.getPojoParameters();
Affirm.affirmEquals("Should have 1 parameter", 1, pojoParameters.size());
Affirm.affirmFalse("Should be nonParameterized parameter", pojoParameters.get(0).isParameterized());
Affirm.affirmEquals("Should be enclosing type", constructor.getParameterTypes()[0], pojoclass.getEnclosingClass().getClazz());
}

@Test
public void shouldHaveTwoParametersWithWhenOneParameterDeclared() {
PojoClass pojoclass = PojoClassFactory.getPojoClass(AClassWithNestedClass.NestedClassWithOneParamConstructor.class);
List<PojoMethod> pojoConstructors = pojoclass.getPojoConstructors();
Affirm.affirmEquals("Should have only one constructor", 1, pojoConstructors.size());
PojoMethod constructor = pojoConstructors.get(0);
List<PojoParameter> pojoParameters = constructor.getPojoParameters();
Affirm.affirmEquals("Should have 2 parameter", 2, pojoParameters.size());
Affirm.affirmFalse("Should be nonParameterized parameter", pojoParameters.get(0).isParameterized());
Affirm.affirmEquals("Should be enclosing type", constructor.getParameterTypes()[0], pojoclass.getEnclosingClass().getClazz());
Affirm.affirmEquals("Should be int type", constructor.getParameterTypes()[1], int.class);
}

@Test
public void shouldBeAbleToConstructNestedChildWithNoParameters() {
PojoClass pojoclass = PojoClassFactory.getPojoClass(AClassWithNestedClass.NestedClass.class);
Object instance = RandomFactory.getRandomValue(pojoclass.getClazz());
Affirm.affirmEquals("Should be same type", pojoclass.getClazz(), instance.getClass());
}

@Test
public void shouldBeAbletoConstructNestedChileWithOneParameter() {
PojoClass pojoclass = PojoClassFactory.getPojoClass(AClassWithNestedClass.NestedClassWithOneParamConstructor.class);
Object instance = RandomFactory.getRandomValue(pojoclass.getClazz());
Affirm.affirmEquals("Should be same type", pojoclass.getClazz(), instance.getClass());
}

@Test
public void shouldBeAbletoConstructNestedChileWithOneGenericParameter() {
PojoClass pojoclass = PojoClassFactory.getPojoClass(AClassWithNestedClass.NestedClassWithOneGenericParamConstructor.class);
Object instance = RandomFactory.getRandomValue(pojoclass.getClazz());
Affirm.affirmEquals("Should be same type", pojoclass.getClazz(), instance.getClass());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
*/
public class PojoPackageImplTest {

private static final int EXPECTED_CLASSES = 59;
private static final int EXPECTED_CLASSES = 61;

private String packageName;
private String expectedToString;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,30 @@

package com.openpojo.reflection.impl.sample.classes;

import java.util.List;

/**
* @author oshoukry
*/
@SuppressWarnings("unused")
public class AClassWithNestedClass {

public class NestedClass {

}

public class NestedClassWithOneParamConstructor {
private NestedClassWithOneParamConstructor(int someParam) {
}
}

public class NestedClassWithOneGenericParamConstructor {
private NestedClassWithOneGenericParamConstructor(List<String> someParam) {
}
}

public static class NestedStaticClass {


}
}

0 comments on commit c506923

Please sign in to comment.