001package ball.databind.ant.taskdefs; 002/*- 003 * ########################################################################## 004 * Data Binding Utilities 005 * $Id: ObjectMapperTask.java 7215 2021-01-03 18:39:51Z ball $ 006 * $HeadURL: svn+ssh://svn.hcf.dev/var/spool/scm/repository.svn/ball-databind/trunk/src/main/java/ball/databind/ant/taskdefs/ObjectMapperTask.java $ 007 * %% 008 * Copyright (C) 2016 - 2021 Allen D. Ball 009 * %% 010 * Licensed under the Apache License, Version 2.0 (the "License"); 011 * you may not use this file except in compliance with the License. 012 * You may obtain a copy of the License at 013 * 014 * http://www.apache.org/licenses/LICENSE-2.0 015 * 016 * Unless required by applicable law or agreed to in writing, software 017 * distributed under the License is distributed on an "AS IS" BASIS, 018 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 019 * See the License for the specific language governing permissions and 020 * limitations under the License. 021 * ########################################################################## 022 */ 023import ball.databind.ObjectMapperFeature; 024import ball.util.ant.taskdefs.AnnotatedAntTask; 025import ball.util.ant.taskdefs.AntTask; 026import ball.util.ant.taskdefs.ClasspathDelegateAntTask; 027import ball.util.ant.taskdefs.ConfigurableAntTask; 028import ball.util.ant.taskdefs.NotNull; 029import ball.util.ant.types.StringAttributeType; 030import com.fasterxml.jackson.databind.JavaType; 031import com.fasterxml.jackson.databind.ObjectMapper; 032import com.fasterxml.jackson.databind.type.TypeFactory; 033import java.io.File; 034import java.util.ArrayList; 035import java.util.Arrays; 036import java.util.Collection; 037import java.util.Map; 038import java.util.SortedMap; 039import java.util.TreeMap; 040import lombok.Getter; 041import lombok.NoArgsConstructor; 042import lombok.NonNull; 043import lombok.RequiredArgsConstructor; 044import lombok.Setter; 045import lombok.ToString; 046import lombok.experimental.Accessors; 047import org.apache.tools.ant.BuildException; 048import org.apache.tools.ant.PropertyHelper; 049import org.apache.tools.ant.Task; 050import org.apache.tools.ant.util.ClasspathUtils; 051 052import static ball.databind.ObjectMapperFeature.MAP; 053import static lombok.AccessLevel.PROTECTED; 054import static org.apache.commons.lang3.StringUtils.isEmpty; 055 056/** 057 * Abstract {@link.uri http://ant.apache.org/ Ant} base {@link Task} for 058 * {@link ObjectMapper} tasks. 059 * 060 * {@ant.task} 061 * 062 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball} 063 * @version $Revision: 7215 $ 064 */ 065@RequiredArgsConstructor(access = PROTECTED) 066public abstract class ObjectMapperTask extends Task 067 implements AnnotatedAntTask, 068 ClasspathDelegateAntTask, 069 ConfigurableAntTask { 070 @Getter @Setter @Accessors(chain = true, fluent = true) 071 private ClasspathUtils.Delegate delegate = null; 072 @Getter @Setter 073 private boolean registerModules = false; 074 private final ArrayList<Setting> settings = new ArrayList<>(); 075 @NonNull 076 protected final ObjectMapper mapper; 077 078 /** 079 * No-argument constructor. 080 */ 081 protected ObjectMapperTask() { this(new ObjectMapper()); } 082 083 public void addConfiguredConfigure(Setting setting) { 084 settings.add(setting); 085 } 086 087 @Override 088 public void init() throws BuildException { 089 super.init(); 090 ClasspathDelegateAntTask.super.init(); 091 ConfigurableAntTask.super.init(); 092 093 try { 094 if (isRegisterModules()) { 095 mapper.registerModules(ObjectMapper.findModules(getClassLoader())); 096 } 097 098 for (Map.Entry<String,Object> entry : 099 getProject().getProperties().entrySet()) { 100 if (MAP.containsKey(entry.getKey())) { 101 ObjectMapperFeature.configure(mapper, 102 MAP.get(entry.getKey()), 103 PropertyHelper.toBoolean(entry.getValue())); 104 } 105 } 106 107 for (Setting setting : settings) { 108 ObjectMapperFeature.configure(mapper, 109 setting.getEnum(), 110 setting.booleanValue()); 111 } 112 } catch (BuildException exception) { 113 throw exception; 114 } catch (Throwable throwable) { 115 throw new BuildException(throwable); 116 } 117 } 118 119 @Override 120 public void execute() throws BuildException { 121 super.execute(); 122 AnnotatedAntTask.super.execute(); 123 } 124 125 /** 126 * {@link ObjectMapper} configuration setting. 127 * 128 * {@bean.info} 129 */ 130 @NoArgsConstructor @ToString 131 public static class Setting extends StringAttributeType { 132 133 /** 134 * Method to get the feature {@link Enum}. 135 * 136 * @return The feature {@link Enum}. 137 */ 138 public Enum<?> getEnum() { return MAP.get(getName()); } 139 140 /** 141 * Method to get the feature boolean value. 142 * 143 * @return The feature boolean value. 144 */ 145 public boolean booleanValue() { 146 return (isEmpty(getValue()) 147 ? true 148 : PropertyHelper.toBoolean(getValue())); 149 } 150 } 151 152 /** 153 * {@link.uri http://ant.apache.org/ Ant} 154 * {@link org.apache.tools.ant.Task} to invoke 155 * {@link ObjectMapper#readValue(File,Class)}. 156 * 157 * {@ant.task} 158 */ 159 @AntTask("om-read-value") 160 @ToString 161 public static class ReadValue extends ObjectMapperTask { 162 @NotNull @Getter @Setter 163 private File file = null; 164 @NotNull @Getter @Setter 165 private String type = null; 166 @Getter @Setter 167 private String collection = null; 168 169 /** 170 * No-argument constructor. 171 */ 172 public ReadValue() { this(new ObjectMapper()); } 173 174 /** 175 * Protected constructor to allow subclasses to specify the 176 * {@link ObjectMapper}. 177 * 178 * @param mapper The {@link ObjectMapper}. 179 */ 180 protected ReadValue(ObjectMapper mapper) { super(mapper); } 181 182 /** 183 * Method to construct a {@link JavaType} from {@code getType()} and 184 * {@code getCollection()}. 185 * 186 * @return The {@link JavaType}. 187 * 188 * @throws Exception If the {@link JavaType} cannot be 189 * constructed. 190 */ 191 protected JavaType getJavaType() throws Exception { 192 TypeFactory factory = mapper.getTypeFactory(); 193 JavaType type = null; 194 195 if (! isEmpty(getCollection())) { 196 type = 197 factory 198 .constructCollectionType(getClassForName(getCollection()) 199 .asSubclass(Collection.class), 200 getClassForName(getType())); 201 } else { 202 type = 203 factory 204 .constructSimpleType(getClassForName(getType()), 205 new JavaType[] { }); 206 } 207 208 return type; 209 } 210 211 @Override 212 public void execute() throws BuildException { 213 super.execute(); 214 215 try { 216 Object value = mapper.readValue(getFile(), getJavaType()); 217 218 log(String.valueOf(value)); 219 } catch (BuildException exception) { 220 throw exception; 221 } catch (Throwable throwable) { 222 throw new BuildException(throwable); 223 } 224 } 225 } 226}