Repository: karaf Updated Branches: refs/heads/karaf-4.1.x 525c99ad9 -> de932d334
[KARAF-5104] Add feature support in karaf:run mojo Project: http://git-wip-us.apache.org/repos/asf/karaf/repo Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/de932d33 Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/de932d33 Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/de932d33 Branch: refs/heads/karaf-4.1.x Commit: de932d3348c20f4cd143ff560612658e93f55aa7 Parents: 525c99a Author: Steinar Bang <[email protected]> Authored: Sat Jun 10 20:44:10 2017 +0200 Committer: Jean-Baptiste Onofré <[email protected]> Committed: Thu Jun 15 07:40:35 2017 +0200 ---------------------------------------------------------------------- .../java/org/apache/karaf/tooling/RunMojo.java | 106 ++++- .../org/apache/karaf/tooling/RunMojoTest.java | 418 +++++++++++++++++++ 2 files changed, 517 insertions(+), 7 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/karaf/blob/de932d33/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/RunMojo.java ---------------------------------------------------------------------- diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/RunMojo.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/RunMojo.java index 16023bf..be62836 100644 --- a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/RunMojo.java +++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/RunMojo.java @@ -40,12 +40,16 @@ import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; +import org.apache.maven.project.MavenProject; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.osgi.util.tracker.ServiceTracker; import java.io.*; +import java.lang.reflect.Method; +import java.net.URI; +import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -74,6 +78,19 @@ public class RunMojo extends MojoSupport { private boolean deployProjectArtifact = true; /** + * A list of URLs referencing feature repositories that will be added + * to the karaf instance started by this goal. + */ + @Parameter + private String[] featureRepositories = null; + + /** + * Comma-separated list of features to install. + */ + @Parameter(defaultValue = "") + private String featuresToInstall = null; + + /** * Define if the Karaf container keep running or stop just after the goal execution */ @Parameter(defaultValue = "true") @@ -124,7 +141,11 @@ public class RunMojo extends MojoSupport { bootFinished = bundleContext.getService(ref); } } - deploy(bundleContext); + + Object featureService = findFeatureService(bundleContext); + addFeatureRepositories(featureService); + deploy(bundleContext, featureService); + addFeatures(featureService); if (keepRunning) main.awaitShutdown(); main.destroy(); @@ -135,10 +156,28 @@ public class RunMojo extends MojoSupport { } } - private void deploy(BundleContext bundleContext) throws MojoExecutionException { + void addFeatureRepositories(Object featureService) throws MojoExecutionException { + if (featureRepositories != null) { + try { + Class<? extends Object> serviceClass = featureService.getClass(); + Method addRepositoryMethod = serviceClass.getMethod("addRepository", URI.class); + + for (String featureRepo : featureRepositories) { + addRepositoryMethod.invoke(featureService, URI.create(featureRepo)); + } + } catch (Exception e) { + throw new MojoExecutionException("Failed to add feature repositories to karaf", e); + } + } + } + + void deploy(BundleContext bundleContext, Object featureService) throws MojoExecutionException { if (deployProjectArtifact) { File artifact = project.getArtifact().getFile(); - if (artifact != null && artifact.exists()) { + File attachedFeatureFile = getAttachedFeatureFile(project); + boolean artifactExists = artifact != null && artifact.exists(); + boolean attachedFeatureFileExists = attachedFeatureFile != null && attachedFeatureFile.exists(); + if (artifactExists) { if (project.getPackaging().equals("bundle")) { try { Bundle bundle = bundleContext.installBundle(artifact.toURI().toURL().toString()); @@ -149,12 +188,30 @@ public class RunMojo extends MojoSupport { } else { throw new MojoExecutionException("Packaging " + project.getPackaging() + " is not supported"); } + } else if (attachedFeatureFileExists) { + addFeaturesAttachmentAsFeatureRepository(featureService, attachedFeatureFile); } else { throw new MojoExecutionException("Project artifact doesn't exist"); } } } + void addFeatures(Object featureService) throws MojoExecutionException { + if (featuresToInstall != null) { + try { + Class<? extends Object> serviceClass = featureService.getClass(); + Method installFeatureMethod = serviceClass.getMethod("installFeature", String.class); + String[] features = featuresToInstall.split(" *, *"); + for (String feature : features) { + installFeatureMethod.invoke(featureService, feature); + Thread.sleep(1000L); + } + } catch (Exception e) { + throw new MojoExecutionException("Failed to add features to karaf", e); + } + } + } + public static void extract(File sourceFile, File targetFolder) throws IOException { if (sourceFile.getAbsolutePath().indexOf(".zip") > 0) { extractZipDistribution(sourceFile, targetFolder); @@ -166,16 +223,14 @@ public class RunMojo extends MojoSupport { return; } - private static void extractTarGzDistribution(File sourceDistribution, File _targetFolder) - throws IOException { + private static void extractTarGzDistribution(File sourceDistribution, File _targetFolder) throws IOException { File uncompressedFile = File.createTempFile("uncompressedTarGz-", ".tar"); extractGzArchive(new FileInputStream(sourceDistribution), uncompressedFile); extract(new TarArchiveInputStream(new FileInputStream(uncompressedFile)), _targetFolder); FileUtils.forceDelete(uncompressedFile); } - private static void extractZipDistribution(File sourceDistribution, File _targetFolder) - throws IOException { + private static void extractZipDistribution(File sourceDistribution, File _targetFolder) throws IOException { extract(new ZipArchiveInputStream(new FileInputStream(sourceDistribution)), _targetFolder); } @@ -301,4 +356,41 @@ public class RunMojo extends MojoSupport { return part != null && !part.isEmpty(); } + private File getAttachedFeatureFile(MavenProject project) { + List<Artifact> attachedArtifacts = project.getAttachedArtifacts(); + for (Artifact artifact : attachedArtifacts) { + if ("features".equals(artifact.getClassifier()) && "xml".equals(artifact.getType())) { + return artifact.getFile(); + } + } + + return null; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) Object findFeatureService(BundleContext bundleContext) { + // Use Object as the service type and use reflection when calling the service, + // because the returned services use the OSGi classloader + ServiceReference ref = bundleContext.getServiceReference(FeaturesService.class); + if (ref != null) { + Object featureService = bundleContext.getService(ref); + return featureService; + } + + return null; + } + + private void addFeaturesAttachmentAsFeatureRepository(Object featureService, File attachedFeatureFile) throws MojoExecutionException { + if (featureService != null) { + try { + Class<? extends Object> serviceClass = featureService.getClass(); + Method addRepositoryMethod = serviceClass.getMethod("addRepository", URI.class); + addRepositoryMethod.invoke(featureService, attachedFeatureFile.toURI()); + } catch (Exception e) { + throw new MojoExecutionException("Failed to register attachment as feature repository", e); + } + } else { + throw new MojoExecutionException("Failed to find the FeatureService when adding a feature repository"); + } + } + } http://git-wip-us.apache.org/repos/asf/karaf/blob/de932d33/tooling/karaf-maven-plugin/src/test/java/org/apache/karaf/tooling/RunMojoTest.java ---------------------------------------------------------------------- diff --git a/tooling/karaf-maven-plugin/src/test/java/org/apache/karaf/tooling/RunMojoTest.java b/tooling/karaf-maven-plugin/src/test/java/org/apache/karaf/tooling/RunMojoTest.java new file mode 100644 index 0000000..f63ac72 --- /dev/null +++ b/tooling/karaf-maven-plugin/src/test/java/org/apache/karaf/tooling/RunMojoTest.java @@ -0,0 +1,418 @@ +package org.apache.karaf.tooling; + +import static org.junit.Assert.*; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Field; +import java.net.URI; +import org.apache.karaf.features.FeaturesService; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.project.MavenProject; +import static org.easymock.EasyMock.*; + +import org.easymock.EasyMock; +import org.easymock.EasyMockSupport; +import org.junit.Test; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; +import org.osgi.framework.ServiceReference; + +public class RunMojoTest extends EasyMockSupport { + + @Test + public void testAddFeatureRepositoriesWithNullRepoList() throws MojoExecutionException { + FeaturesService featureService = mock(FeaturesService.class); + replay(featureService); + + RunMojo mojo = new RunMojo(); + mojo.addFeatureRepositories(featureService); + verify(featureService); // Non-nice easymock mock will fail on any call + } + + @Test + public void testAddFeatureRepositoriesWithEmptyRepoListAndNullFeatureService() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, MojoExecutionException { + RunMojo mojo = new RunMojo(); + String[] empty = new String[0]; + setPrivateField(mojo, "featureRepositories", empty); + try { + mojo.addFeatureRepositories(null); + fail("Expected MojoExecutionException to be thrown"); + } catch(MojoExecutionException e) { + assertEquals("Failed to add feature repositories to karaf", e.getMessage()); + } + } + + @Test + public void testAddFeatureRepositoriesWithEmptyRepoList() throws MojoExecutionException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + FeaturesService featureService = mock(FeaturesService.class); + replay(featureService); + + RunMojo mojo = new RunMojo(); + String[] empty = new String[0]; + setPrivateField(mojo, "featureRepositories", empty); + mojo.addFeatureRepositories(featureService); + verify(featureService); // Non-nice easymock mock will fail on any call + } + + @Test + public void testAddFeatureRepositories() throws Exception { + FeaturesService featureService = niceMock(FeaturesService.class); + featureService.addRepository(anyObject(URI.class)); + EasyMock.expectLastCall().once(); + replay(featureService); + + RunMojo mojo = new RunMojo(); + String[] features = { "liquibase-core", "ukelonn" }; + setPrivateField(mojo, "featureRepositories", features); + mojo.addFeatureRepositories(featureService); + verify(featureService); + } + + @Test + public void testDeployWithDeployProjectArtifactFalse() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, MojoExecutionException { + BundleContext context = mock(BundleContext.class); + RunMojo mojo = new RunMojo(); + setPrivateField(mojo, "deployProjectArtifact", false); + mojo.deploy(context, null); + } + + @Test + public void testDeployWithNullArtifact() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + BundleContext context = mock(BundleContext.class); + Artifact artifact = mock(Artifact.class); + RunMojo mojo = new RunMojo(); + MavenProject project = new MavenProject(); + project.setArtifact(artifact); + setInheritedPrivateField(mojo, "project", project); + try { + mojo.deploy(context, null); + fail("Expected MojoExecutionException"); + } catch (MojoExecutionException e) { + assertEquals("Project artifact doesn't exist", e.getMessage()); + } + } + + @Test + public void testDeployWithNonExistingArtifact() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + BundleContext context = mock(BundleContext.class); + Artifact artifact = mock(Artifact.class); + File artifactFile = mock(File.class); + expect(artifact.getFile()).andReturn(artifactFile); + replay(artifact); + RunMojo mojo = new RunMojo(); + MavenProject project = new MavenProject(); + project.setArtifact(artifact); + setInheritedPrivateField(mojo, "project", project); + try { + mojo.deploy(context, null); + fail("Expected MojoExecutionException"); + } catch (MojoExecutionException e) { + assertEquals("Project artifact doesn't exist", e.getMessage()); + } + } + + @Test + public void testDeployWithExistingArtifactButProjectNotBundle() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + BundleContext context = mock(BundleContext.class); + Artifact artifact = mock(Artifact.class); + File artifactFile = mock(File.class); + expect(artifactFile.exists()).andReturn(true); + replay(artifactFile); + expect(artifact.getFile()).andReturn(artifactFile); + replay(artifact); + RunMojo mojo = new RunMojo(); + MavenProject project = new MavenProject(); + project.setArtifact(artifact); + setInheritedPrivateField(mojo, "project", project); + try { + mojo.deploy(context, null); + fail("Expected MojoExecutionException"); + } catch (MojoExecutionException e) { + assertEquals("Packaging jar is not supported", e.getMessage()); + } + } + + @Test + public void testDeployWithExistingArtifactFailsInInstall() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + BundleContext context = mock(BundleContext.class); + Artifact artifact = mock(Artifact.class); + File artifactFile = niceMock(File.class); + expect(artifactFile.exists()).andReturn(true); + replay(artifactFile); + expect(artifact.getFile()).andReturn(artifactFile); + replay(artifact); + RunMojo mojo = new RunMojo(); + MavenProject project = new MavenProject(); + project.setPackaging("bundle"); + project.setArtifact(artifact); + setInheritedPrivateField(mojo, "project", project); + try { + mojo.deploy(context, null); + fail("Expected MojoExecutionException"); + } catch (MojoExecutionException e) { + assertEquals("Can't deploy project artifact in container", e.getMessage()); + } + } + + @Test + public void testDeployWithExistingArtifact() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, IOException, BundleException, MojoExecutionException { + BundleContext context = niceMock(BundleContext.class); + Bundle bundle = niceMock(Bundle.class); + expect(context.installBundle(anyString())).andReturn(bundle); + replay(context); + Artifact artifact = mock(Artifact.class); + File artifactFile = File.createTempFile("fake-bundle", ".jar"); + try { + expect(artifact.getFile()).andReturn(artifactFile); + replay(artifact); + RunMojo mojo = new RunMojo(); + MavenProject project = new MavenProject(); + project.setPackaging("bundle"); + project.setArtifact(artifact); + setInheritedPrivateField(mojo, "project", project); + replay(bundle); + mojo.deploy(context, null); + verify(bundle); + } finally { + artifactFile.delete(); + } + } + + @Test + public void testDeployWithPomArtifactAndAttachedFeatureXmlNoFeatureService() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, IOException, BundleException, MojoExecutionException { + File artifactFeaturesAttachmentFile = File.createTempFile("someproject-features", ".xml"); + try { + BundleContext context = niceMock(BundleContext.class); + Bundle bundle = niceMock(Bundle.class); + expect(context.installBundle(anyString())).andReturn(bundle); + replay(context); + Artifact artifact = niceMock(Artifact.class); + replay(artifact); + Artifact artifactFeaturesAttachment = mock(Artifact.class); + expect(artifactFeaturesAttachment.getFile()).andReturn(artifactFeaturesAttachmentFile); + expect(artifactFeaturesAttachment.getClassifier()).andReturn("features"); + expect(artifactFeaturesAttachment.getType()).andReturn("xml"); + replay(artifactFeaturesAttachment); + + RunMojo mojo = new RunMojo(); + MavenProject project = new MavenProject(); + project.setPackaging("pom"); + project.setArtifact(artifact); + project.addAttachedArtifact(artifactFeaturesAttachment); + setInheritedPrivateField(mojo, "project", project); + replay(bundle); + try { + mojo.deploy(context, null); + fail("Expected MojoExecutionException"); + } catch (MojoExecutionException e) { + assertEquals("Failed to find the FeatureService when adding a feature repository", e.getMessage()); + } + } finally { + artifactFeaturesAttachmentFile.delete(); + } + } + + @SuppressWarnings("unchecked") + @Test + public void testDeployWithPomArtifactAndAttachedFeatureXmlRepoRegistrationFails() throws Exception { + File artifactFeaturesAttachmentFile = File.createTempFile("someproject-features", ".xml"); + try { + FeaturesService featureService = niceMock(FeaturesService.class); + featureService.addRepository(anyObject(URI.class)); + EasyMock.expectLastCall().andThrow(new Exception("Not a feature repository")); + replay(featureService); + ServiceReference<FeaturesService> ref = niceMock(ServiceReference.class); + BundleContext context = niceMock(BundleContext.class); + expect(context.getServiceReference(eq(FeaturesService.class))).andReturn(ref); + expect(context.getService(eq(ref))).andReturn(featureService); + replay(context); + Artifact artifact = niceMock(Artifact.class); + replay(artifact); + Artifact artifactFeaturesAttachment = mock(Artifact.class); + expect(artifactFeaturesAttachment.getFile()).andReturn(artifactFeaturesAttachmentFile); + expect(artifactFeaturesAttachment.getClassifier()).andReturn("features"); + expect(artifactFeaturesAttachment.getType()).andReturn("xml"); + replay(artifactFeaturesAttachment); + + RunMojo mojo = new RunMojo(); + MavenProject project = new MavenProject(); + project.setPackaging("pom"); + project.setArtifact(artifact); + project.addAttachedArtifact(artifactFeaturesAttachment); + setInheritedPrivateField(mojo, "project", project); + try { + mojo.deploy(context, featureService); + fail("Expected MojoExecutionException"); + } catch (MojoExecutionException e) { + assertEquals("Failed to register attachment as feature repository", e.getMessage()); + } + } finally { + artifactFeaturesAttachmentFile.delete(); + } + } + + @SuppressWarnings("unchecked") + @Test + public void testDeployWithPomArtifactAndAttachedFeatureXmlAndNoFeatures() throws Exception { + File artifactFeaturesAttachmentFile = File.createTempFile("someproject-features", ".xml"); + try { + FeaturesService featureService = niceMock(FeaturesService.class); + replay(featureService); + ServiceReference<FeaturesService> ref = niceMock(ServiceReference.class); + BundleContext context = niceMock(BundleContext.class); + expect(context.getServiceReference(eq(FeaturesService.class))).andReturn(ref); + expect(context.getService(eq(ref))).andReturn(featureService); + replay(context); + Artifact artifact = niceMock(Artifact.class); + replay(artifact); + Artifact artifactFeaturesAttachment = mock(Artifact.class); + expect(artifactFeaturesAttachment.getFile()).andReturn(artifactFeaturesAttachmentFile); + expect(artifactFeaturesAttachment.getClassifier()).andReturn("features"); + expect(artifactFeaturesAttachment.getType()).andReturn("xml"); + replay(artifactFeaturesAttachment); + + RunMojo mojo = new RunMojo(); + MavenProject project = new MavenProject(); + project.setPackaging("pom"); + project.setArtifact(artifact); + project.addAttachedArtifact(artifactFeaturesAttachment); + setInheritedPrivateField(mojo, "project", project); + mojo.deploy(context, featureService); + verify(featureService); + } finally { + artifactFeaturesAttachmentFile.delete(); + } + } + + @SuppressWarnings("unchecked") + @Test + public void testDeployWithPomArtifactAndAttachedFeatureXml() throws Exception { + File artifactFeaturesAttachmentFile = File.createTempFile("someproject-features", ".xml"); + try { + FeaturesService featureService = niceMock(FeaturesService.class); + replay(featureService); + ServiceReference<FeaturesService> ref = niceMock(ServiceReference.class); + BundleContext context = niceMock(BundleContext.class); + expect(context.getServiceReference(eq(FeaturesService.class))).andReturn(ref); + expect(context.getService(eq(ref))).andReturn(featureService); + replay(context); + Artifact artifact = niceMock(Artifact.class); + replay(artifact); + Artifact artifactFeaturesAttachment = mock(Artifact.class); + expect(artifactFeaturesAttachment.getFile()).andReturn(artifactFeaturesAttachmentFile); + expect(artifactFeaturesAttachment.getClassifier()).andReturn("features"); + expect(artifactFeaturesAttachment.getType()).andReturn("xml"); + replay(artifactFeaturesAttachment); + + RunMojo mojo = new RunMojo(); + MavenProject project = new MavenProject(); + project.setPackaging("pom"); + project.setArtifact(artifact); + project.addAttachedArtifact(artifactFeaturesAttachment); + setInheritedPrivateField(mojo, "project", project); + setPrivateField(mojo, "featuresToInstall", "liquibase-core, ukelonn-db-derby-test, ukelonn"); + String[] featureRepos = { "mvn:org.ops4j.pax.jdbc/pax-jdbc-features/LATEST/xml/features" }; + setPrivateField(mojo, "featureRepositories", featureRepos); + mojo.deploy(context, featureService); + verify(featureService); + } finally { + artifactFeaturesAttachmentFile.delete(); + } + } + + /** + * Just check the string split behaviour on various feature strings. + */ + @Test + public void testStringSplit() { + String[] split1 = "liquibase-core, ukelonn-db-derby-test, ukelonn".split(" *, *"); + assertEquals(3, split1.length); + String[] split2 = "liquibase-core".split(" *, *"); + assertEquals(1, split2.length); + String[] split3 = " ".split(" *, *"); + assertEquals(1, split3.length); + String[] split4 = " , ".split(" *, *"); + assertEquals(0, split4.length); + String[] split5 = "liquibase-core, ".split(" *, *"); + assertEquals(1, split5.length); + String[] split6 = "liquibase-core, , ".split(" *, *"); + assertEquals(1, split6.length); + } + + @Test + public void testAddFeaturesNullFeaturesToInstall() throws MojoExecutionException { + FeaturesService featureService = mock(FeaturesService.class); + replay(featureService); + + RunMojo mojo = new RunMojo(); + mojo.addFeatures(featureService); + verify(featureService); // Non-nice easymock mock will fail on any call + } + + @Test + public void testAddFeaturesNullFeatureService() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + RunMojo mojo = new RunMojo(); + setPrivateField(mojo, "featuresToInstall", "liquibase-core, ukelonn-db-derby-test, ukelonn"); + + try { + mojo.addFeatures(null); + } catch (MojoExecutionException e) { + assertEquals("Failed to add features to karaf", e.getMessage()); + } + } + + @Test + public void testAddFeatures() throws Exception { + FeaturesService featureService = mock(FeaturesService.class); + featureService.installFeature(anyString()); + EasyMock.expectLastCall().times(3); + replay(featureService); + + RunMojo mojo = new RunMojo(); + setPrivateField(mojo, "featuresToInstall", "liquibase-core, ukelonn-db-derby-test, ukelonn"); + mojo.addFeatures(featureService); + verify(featureService); + } + + @Test + public void testFindFeatureServiceNullServiceRef() { + BundleContext context = niceMock(BundleContext.class); + replay(context); + + RunMojo mojo = new RunMojo(); + Object service = mojo.findFeatureService(context); + assertNull(service); + } + + @SuppressWarnings("unchecked") + @Test + public void testFindFeatureService() { + FeaturesService featureService = niceMock(FeaturesService.class); + replay(featureService); + ServiceReference<FeaturesService> ref = niceMock(ServiceReference.class); + BundleContext context = niceMock(BundleContext.class); + expect(context.getServiceReference(eq(FeaturesService.class))).andReturn(ref); + expect(context.getService(eq(ref))).andReturn(featureService); + replay(context); + + RunMojo mojo = new RunMojo(); + Object service = mojo.findFeatureService(context); + assertNotNull(service); + } + + private void setPrivateField(Object obj, String fieldName, Object value) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + Field field = obj.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(obj, value); + } + + private void setInheritedPrivateField(Object obj, String fieldName, Object value) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + Field field = obj.getClass().getSuperclass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(obj, value); + } + +}
